Skip to content

feat(billing): bootstrap Stripe Checkout tenant identity - #573

Draft
seonghobae wants to merge 12 commits into
feat/stripe-webhook-reconciliation-queue-488from
feat/stripe-checkout-identity-bootstrap-488
Draft

feat(billing): bootstrap Stripe Checkout tenant identity#573
seonghobae wants to merge 12 commits into
feat/stripe-webhook-reconciliation-queue-488from
feat/stripe-checkout-identity-bootstrap-488

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Buyer/data-integrity objective

Refs #488. This stacked Draft closes the first-subscription identity bootstrap gap between a successful local Checkout attempt and later authoritative Stripe Subscription reconciliation. A signed Checkout event can supply provider Customer/Subscription identities, but it cannot choose a ScopeWeave organization by metadata or arrival order; tenant authority comes from exactly one server-recorded successful local Checkout attempt whose provider_session_id matches the verified checkout.session.completed Session ID.

Exact current stack

  • protected develop: 2c328875e00e86537df3e965170be80532571cad;
  • exact parent/base feat(billing): queue verified Stripe reconciliation triggers #570: feat/stripe-webhook-reconciliation-queue-488@b8a5dab7117ee30967833abc5c8607dec6490cb8;
  • exact contributor head at opening: 7e480f0c10ac5598e641fff03d6f7d7a8afca8f2;
  • fresh parent→child comparison before opening: ahead 10, behind 0, exact parent as merge base, 10 changed paths;
  • state: Draft.

Any parent, contributor-head, protected-base, review, or check movement invalidates ancestry- and head-sensitive evidence until freshly revalidated.

Implemented authority contract

server/stripe_checkout_identity_bootstrap.mjs:

  • accepts only verified checkout.session.completed Subscription-mode Checkout objects with bounded canonical Session, Customer, and Subscription identifiers;
  • independently rechecks the immutable verified-event ledger row for exact event type, object type, and Session ID;
  • resolves tenant authority only from one unique billing_checkout_attempts row already recorded as provider_succeeded for that exact Stripe Session ID;
  • rejects missing local ownership, duplicate/ambiguous successful Session ownership, Customer→organization rebinding, and Subscription→Customer rebinding;
  • writes the existing normalized billing_stripe_customers and billing_stripe_subscriptions identity tables instead of creating duplicate ownership state;
  • preserves immutable first-observed evidence on exact replay; and
  • never writes orgs.plan, entitlement claims, session authority, membership, or RBAC.

The webhook bootstrap installs the normalized Subscription identity schema before recorder configuration, performs Checkout identity binding inside the recorder's existing outer SQLite savepoint, then creates the pending reconciliation trigger. A downstream identity or trigger failure therefore rolls verified event/delivery evidence, provider identity, and queued work back together.

server/stripe_webhook_reconciliation_queue.mjs now maps subscription-mode checkout.session.completed to its Subscription ID only as a reconciliation trigger. Payment/setup Checkout completion remains non-authoritative and produces no Subscription work.

TDD and regression evidence

  • test-only commit f316a1ec44b0d08cea6bb1f451901f9082d8ec0e introduced the missing-module Checkout identity contract before production implementation;
  • d0e51bf77787336402244b4eaa5f52ab9223ac37 added the isolated normalized binder;
  • 811ca9c85d50a26c8822dfbed60a7e8d5203c6a8 strengthened the real production webhook bootstrap contract before runtime wiring, including an injected SQLite second-write failure that requires event, delivery, identity, and trigger state to disappear together;
  • later commits wired Checkout trigger extraction and the production bootstrap ordering/atomicity;
  • focused behavior covers successful bootstrap, exact replay, verified-event/session mismatch, missing event, wrong event type/mode, ambiguous successful Session ownership, cross-tenant rebinding, expanded/malformed identities, plan non-mutation, and rollback after a real SQLite trigger failure.

package.json, tests/unit/stripe-checkout-identity-bootstrap-package-contract.test.mjs, and tests/unit/coverage-script-contract.test.mjs lock the behavior test into normal unit CI and c8 while instrumenting server/stripe_checkout_identity_bootstrap.mjs as owned production code.

Standards and scope boundary

docs/doctoring/stripe-checkout-identity-bootstrap.md records active-PR versus protected-shipped truth, the dual-source authority chain, nested savepoint atomicity, rollback semantics, and APA 7 references to current Stripe Checkout/Event documentation and SQLite savepoints.

This slice does not consume the pending reconciliation queue, change retry/backoff/dead-letter state, or itself evaluate/grant entitlement. #569 remains the current-provider reconciliation boundary; #570 owns durable verified-event triggers. Subsequent work must still implement worker claiming/completion and final out-of-order convergence acceptance.

Current evidence boundary

Opening this PR creates fresh repository/organization checks for the exact contributor head. Until every applicable exact-head deterministic/browser/coverage/docstring/CodeQL/SAST/security/dependency/supply-chain/package/provenance gate is terminal and substantive, valid findings are zero, and qualifying independent current-head approval exists under live governance, all pending/queued/absent/stale/predecessor/status-only/model-only evidence is non-passing.

Remain Draft and do not integrate independently of #570/#569/#568 and the preceding #488 billing stack.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f5d35a8c-9835-4da8-9bb7-f9a77785f446

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@opencode-agent opencode-agent Bot added area: auth Authentication, authorization, identity, or tenant isolation priority: medium Normal-priority or P2 work status: draft Draft pull request type: feature New or expanded product capability labels Aug 22, 2026
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

1 similar comment
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: auth Authentication, authorization, identity, or tenant isolation priority: medium Normal-priority or P2 work status: draft Draft pull request type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant