Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions GITHUB_ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Every issue inherits `AGENTS.md` and the definition of done in `IMPLEMENTATION_P
| 10 | ABUSE-001 | Enforce native App Check and privacy-preserving abuse limits | P0 | L | partial: Enterprise browser source/tests tracked in [#159](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/159); provider config, native enforcement, rate limits, and live proof open | CI-001 baseline |
| 11 | PAY-001 | Add strict request schemas and immutable monetary snapshots | P0 | L | partial: PAY-001A source/tests tracked in [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157); B/C/D and endpoint adoption open | ABUSE-001 interface agreed |
| 12 | PROMO-001 | Disable unmodeled Stripe promotions until discounts are authoritative | P0 | S | source/tests complete under open GitHub issue #102; provider inventory and deployment remain owner action | PAY-001 for any future discount contract |
| 13 | PAY-002 | Implement idempotent payment commands and explicit state machines | P0 | L | ready after PAY-001 | CONFIG-001, PAY-001 |
| 13 | PAY-002 | Implement idempotent payment commands and explicit state machines | P0 | L | partial: PAY-002A1 pure source/tests tracked in [#161](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/161); runtime adoption, migration, and B-D open | CONFIG-001, PAY-001 |
| 14 | PAY-003 | Build idempotent, async-aware Stripe webhook ingestion | P0 | L | PAY-003A source merged in #101; PAY-003B/C remain open; not deployed | CONFIG-001, PAY-001/PAY-002 target contract |
| 15 | RACE-001 | Add transactional race-capacity reservations | P0 | L | proposed | PAY-002, PAY-003 event contract |
| 16 | MERCH-001 | Add SKU variants and transactional inventory reservations | P0 | L | proposed | PAY-002, PAY-003 event contract |
Expand Down Expand Up @@ -624,16 +624,22 @@ The local webhook/creator patch is a safety default, not a complete discount fea
## PAY-002 — Implement idempotent payment commands and explicit state machines

**Labels:** `priority:P0`, `type:reliability`, `type:security`, `area:stripe`, `area:firebase`, `size:L`, `needs-migration`
**Status:** Ready after PAY-001
**Status:** Partial. PAY-002A1 pure source/tests are tracked in live [#161](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/161). Runtime adoption, real legacy inventory/migration, command identity, and checkout sagas remain open.
**Depends on:** CONFIG-001 and PAY-001

### Current atomic boundary

PAY-002A1 defines only a dependency-free version-1 target: separate payment, registration, fulfillment, confirmed-refund, and per-dispute reducers; fixed cross-dimension validation; and a synthetic legacy classifier/redacted aggregate report. Orders/registrations have no canonical singular `disputeStatus`; each dispute is validated separately against paid payment context. Operational `fulfilled`, `transferred`, and `cancelled` legacy values require separate compatible payment evidence rather than manufacturing payment state. It does not import Firebase/Stripe, expose a Function, change the webhook, write a compatibility field, enumerate a real record, or deploy.

The next boundaries remain separate. A later inventory/migration child must use #113-approved data categories and a dry-run before writes. PAY-002B owns caller-scoped command/attempt identity and idempotency journals. PAY-002C/D own persistence-first race/shop sagas. PAY-003B/#106 owns webhook adoption and Stripe API-version adaptation. PAY-004/PAY-005 own cancellation and refund operations.

### Problem

Checkout Session, Stripe Product/Price/Payment Link, and Refund creation have no idempotency keys. One overloaded `status` field mixes payment, registration, fulfillment, cancellation, refund, transfer, and dispute state. Network loss/retry can duplicate external operations; impossible transitions are currently allowed.

### Scope

- Define separate `paymentStatus`, `registrationStatus`, `fulfillmentStatus`, `refundStatus`, and `disputeStatus` with an allowed transition matrix.
- Define separate `paymentStatus`, `registrationStatus`, `fulfillmentStatus`, confirmed `refundStatus`, and one record/state per dispute with allowed structural transition matrices. Any singular dispute summary is derived compatibility only.
- Keep/derive legacy `status` during an additive migration.
- Require client/admin `commandId` UUIDs; hash caller scope + ID into `checkoutRequests`/`commands` records with payload fingerprint.
- Reusing the same ID/payload returns the same result; different payload fails.
Expand Down
17 changes: 9 additions & 8 deletions GITHUB_ISSUE_SLICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de
| PAY-001B | proposed; PAY-001A | Apply race/volunteer/free schemas, validate server event custom fields/options, and persist price/waiver snapshots. | Positive/hostile dynamic-field and snapshot tests. |
| PAY-001C | proposed; PAY-001A | Apply merchandise/variant/quantity schemas and immutable merchandise price snapshots. | Variant/quantity/money/payload tests. |
| PAY-001D | proposed; PAY-001A, AUTH-003A | Apply bounded schemas to lookup/refund/cancel/substitute/late/comp/role/tracking/export commands. | Endpoint matrix with hostile/boundary/no-side-effect tests. |
| PAY-002A | proposed; PAY-001A | Build pure separate payment/registration/fulfillment/refund/dispute reducers and additive legacy mapping. | Exhaustive allowed/forbidden/reordered transition tests and dry-run map. |
| PAY-002B | proposed; PAY-002A | Build caller-scoped command journal, UUID/payload fingerprint, same-result replay, conflict rejection, lease/attempt/error/audit, and Stripe key scheme. | Concurrent duplicate/conflict and injected-failure emulator tests. |
| PAY-002A1 | source/tests tracked in live [#161](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/161); PAY-001A; no runtime adoption/migration/deploy | Build pure version-1 payment/registration/fulfillment/confirmed-refund/per-dispute reducers, cross-dimension validation, and a synthetic legacy classifier/redacted aggregate report. | Exhaust every state pair, retry/reorder/terminal/composite/legacy/hostile-input case; no Firebase/Stripe/logger call or record patch. |
| PAY-002A2 | proposed; PAY-002A1, #113 owner-approved inventory | Use an owner-approved private read-only inventory for any real legacy/provider references (no mutation/export or copying into tests/issues), define one context-aware compatibility derivation, and use only synthetic emulator fixtures for the dry-run/idempotent migration plan. | Redacted counts/reasons for every approved fixture; repeat synthetic dry-run is identical; no production write until separately approved. |
| PAY-002B | proposed; PAY-002A1 | Build caller-scoped command journal, UUID/payload fingerprint, same-result replay, conflict rejection, lease/attempt/error/audit, and Stripe key scheme. | Concurrent duplicate/conflict and injected-failure emulator tests. |
| PAY-002C | proposed; PAY-001B, PAY-002B, RACE-001B | Convert race checkout to persistence-first record/hold plus deterministic Stripe Session saga. | One record/Session on retry at every failure boundary. |
| PAY-002D | proposed; PAY-001C, PAY-002B, MERCH-001B | Convert merchandise/catalog creation to persistence-first order/hold plus deterministic Stripe keys. | One order/Session/catalog object on retry; failure recovery tests. |

Expand All @@ -70,11 +71,11 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de
| ID | Status/dependency | Bounded deliverable | Close evidence |
| --- | --- | --- | --- |
| PAY-003A | source merged in [#101](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/101) via [PR #140](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/140); not deployed | Review/land current ingress slice: signature/method, explicit livemode, payment mode, event ledger, reference resolution, money/adjustment checks, monotonic refunds, terminal guards, quarantine, generic errors, webhook-only secret. | Node 20 Functions lint and signed positive/negative/duplicate/out-of-order unit suite passed; protected deployment, Stripe destination rehearsal, and live verification remain open. |
| PAY-003B | proposed; PAY-002A–D, RACE/MERCH reducers | Move event handling to strict versioned schemas and canonical reducers; atomically finalize/release counters and outbox projections. | Emulator transactions for both domains, distinct duplicates, reorder, async and terminal cases. |
| PAY-003B | proposed; PAY-002A1, PAY-002B-D, RACE-001B, MERCH-001B; PAY-002A2/#113 before any legacy/provider-path adoption | Inventory/validate the Stripe endpoint Event API version, move handling to strict versioned schemas/canonical reducers, and atomically finalize/release counters and outbox projections. Same-state Events must still apply monotonic amount/evidence changes after Event-ID dedupe. | Versioned/mismatch signed fixtures, emulator transactions for both domains, distinct duplicates, reorder, direct async failure, same-state higher partial-refund total, inquiry escalation, late win, and terminal cases. |
| PAY-003C | owner_action; A/B, CI-001A | Add retry/quarantine worker/lease semantics, TTL/dead-letter monitoring, and Stripe CLI test-mode delivery rehearsal. | Redacted signed immediate/delayed/retry/rotation evidence and alerts. |
| RACE-001A | proposed; PAY-002A | Add capacity/hold schema, expiry/indexes, compatibility reader, and dry-run counter backfill. | Full/closed/legacy fixture report and idempotent rerun. |
| RACE-001B | proposed; A, PAY-002B | Implement transaction-safe reserve/confirm/release across paid/free/comp/volunteer/admin paths. | Repeated concurrent last-seat, duplicate, expiry and nonnegative-counter tests. |
| MERCH-001A | proposed; PAY-001C, PAY-002A | Add canonical SKU/variant and conventional `onHand`, `reserved`, `sold` schema plus catalog migration: `available = onHand - reserved`. | Legacy/size/color/zero-stock migration fixtures and invariant report. |
| RACE-001A | proposed; PAY-002A1, PAY-002A2 for legacy/backfill adoption | Add capacity/hold schema, expiry/indexes, compatibility reader, and dry-run counter backfill. | Full/closed/legacy fixture report and idempotent rerun. |
| RACE-001B | proposed; RACE-001A, PAY-002B | Implement transaction-safe reserve/confirm/release across paid/free/comp/volunteer/admin paths. | Repeated concurrent last-seat, duplicate, expiry and nonnegative-counter tests. |
| MERCH-001A | proposed; PAY-001C, PAY-002A1, PAY-002A2 for legacy/backfill adoption | Add canonical SKU/variant and conventional `onHand`, `reserved`, `sold` schema plus catalog migration: `available = onHand - reserved`. | Legacy/size/color/zero-stock migration fixtures and invariant report. |
| MERCH-001B | proposed; A, PAY-002B | Implement deterministic multi-SKU reserve; on paid decrement `reserved` and `onHand`, increment `sold`; release only `reserved`; approved restock increments `onHand`. | Concurrent last-SKU/multi-line/retry/return tests; no negative stock. |
| PAY-004A | proposed; PAY-002B/C, RACE-001B | Implement one-record cancellation that expires Session/releases hold with already-paid/expired/network race recovery. | Retry and payment/cancel race tests; no resurrection. |
| PAY-004B | proposed; A, RACE/MERCH services | Implement bulk event/product closure as bounded idempotent jobs over active Sessions/holds. | Partial failure/resume/rerun report. |
Expand All @@ -84,8 +85,8 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de

| ID | Status/dependency | Bounded deliverable | Close evidence |
| --- | --- | --- | --- |
| PAY-005A | proposed; PAY-001D, PAY-002A/B | Add idempotent refund commands, remaining-balance/concurrency validation, stable Stripe keys, and event-finalized totals. | Same/conflicting/concurrent partial/full/timeout tests. |
| PAY-005B | proposed; PAY-003B | Model dispute lifecycle for orders and registrations with finance alert references. | Duplicate/reordered created/updated/lost/won fixtures. |
| PAY-005A | proposed; PAY-001D, PAY-002A1, PAY-002B, PAY-003B | Add idempotent refund commands, remaining-balance/concurrency validation, stable Stripe keys, and event-finalized totals. | Same/conflicting/concurrent partial/full/timeout and repeated `partially_refunded` status with increasing confirmed total tests. |
| PAY-005B | proposed; PAY-003B | Model per-dispute lifecycle for orders and registrations with finance alert references. | Duplicate/reordered warning lifecycle, inquiry escalation, created/updated/lost/won, rare lost-to-won late win, and `prevented` only under an explicitly validated upgraded webhook Event version. |
| PAY-005C | proposed; A/B | Build read-only scheduled/operator reconciliation and mismatch/quarantine report. | Orphan/mismatch/refund/event/counter synthetic report. |
| PAY-005D | proposed; C, AUTH-003B | Build separately authorized idempotent repair commands with reason and append audit. | Dry-run/apply/rerun and forbidden-capability tests. |
| MAIL-001A | proposed; PAY-003B | Build deterministic escaped transactional outbox and truthful queued/delivery state for registration/order confirmation. | Retry/concurrency/hostile-HTML/provider-failure tests. |
Expand Down
4 changes: 2 additions & 2 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Exit gate:
- Concurrent last-seat and last-SKU tests prove no oversell.
- Session creation is persistence-first, and known failures release holds once.

**Current work:** A PAY-003 webhook safety slice is implemented and unit-verified in this repository pass after the high-level design was recorded. It must not be treated as the complete payment core until PAY-001/PAY-002, capacity, inventory, provider/emulator integration, and production operations close.
**Current work:** A PAY-003 webhook safety slice is implemented and unit-verified. PAY-002A1 is tracked in live [#161](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/161) for the pure versioned structural transition contract and synthetic legacy classification only. It does not prove duplicate Events/commands, evidence, authorization, provider state, or policy. Runtime adoption, command identity, real migration, capacity, inventory, provider/emulator integration, and production operations remain open.

### Phase 3 — Complete lifecycle and customer safety

Expand Down Expand Up @@ -213,7 +213,7 @@ The first tranche deliberately combines one urgent safety repair with the most c
3. **SEC-001 — Firestore trust boundaries:** #100 merged through [PR #123](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/123) at `a7fc301e85b0aeabe396e771faea21d3fc8e7b2b`. Source and 295 Rules tests remove recursive browser-admin authority. Firebase deployment explicitly skipped, so deployed/live Rules remain unproven under #105.
4. **PROMO-001 — fail-safe monetary policy:** [#102](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/102) disables promotion entry and automatic tax in both current creators, adds exact payload tests, and quarantines unknown or nonzero discount/tax/shipping adjustments on success, failure, and expiry. The private pre-change Session/provider inventory, protected deployment, provider readback, and live verification remain owner actions; no discount, tax, or shipping feature is authorized.
5. **Identity/config next:** AUTH-001A [#98](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/98) merged at `ce22c110`, proving source/tests for unverified-target rejection at the existing role-grant endpoints. Its Firebase deployment skipped, so backend-live status is unproven and the remaining AUTH-001 parent work stays open. CONFIG-001A merged through [#149](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/149) / PR #150 as `2c62b8dd`, but remains undeployed. CONFIG-001B1 is tracked in [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151) for fail-closed read-only admission; B2 retains the protected audited operator control, provider-object recovery, and drill. Follow the live issues and do not duplicate these slices.
6. **PAY-001/PAY-002:** PAY-001A source/tests are tracked in [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157) as the shared validation/logging foundation. PAY-001B/C/D must still wire exact endpoint schemas and immutable snapshots before PAY-002 can make checkout creation, refunds, and later handlers idempotent.
6. **PAY-001/PAY-002:** PAY-001A source/tests are tracked in [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157) as the shared validation/logging foundation. PAY-002A1 is tracked in [#161](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/161) for pure separate state reducers and synthetic legacy classification. PAY-001B/C/D must still wire exact endpoint schemas/snapshots; PAY-002B-D must add command identity and persistence-first sagas; PAY-003B must adopt the shared reducer. No current endpoint or record changes in A1.
7. **Then:** RACE-001 and MERCH-001 transactional reservations.

Why this order: SAFETY-001 removes immediate accidental-production and callback hazards without schema impact. PAY-003 closes the most dangerous “unpaid looks paid” and replay gaps while establishing test fixtures. The subsequent trust-boundary and command/state work completes the surrounding architecture; no live launch is authorized by the partial webhook patch alone.
Expand Down
Loading
Loading