Skip to content

feat(billing): persist transactional Stripe entitlement claims - #564

Draft
seonghobae wants to merge 7 commits into
feat/stripe-invoice-current-projection-488from
feat/stripe-entitlement-claim-ledger-488
Draft

feat(billing): persist transactional Stripe entitlement claims#564
seonghobae wants to merge 7 commits into
feat/stripe-invoice-current-projection-488from
feat/stripe-entitlement-claim-ledger-488

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Buyer/data-integrity objective

Refs #488. This Draft child of #563 persists deterministic Stripe entitlement-policy decisions as append-only tenant-bound claim evidence. It selects current accepted Subscription/Invoice evidence itself, preserves exact source provenance, uses optimistic previous-decision concurrency to reject competing reconciliation, atomically advances a per-Subscription current head, and still does not mutate plan/session/RBAC authority or directly grant product access.

Exact current stack

  • exact parent/base feat(billing): project current Stripe invoice evidence #563: feat/stripe-invoice-current-projection-488@74965da5be2dc78f29f73cece891d49b4527fc7e;
  • exact contributor head: c176efda6abbd3796fab776484422bb8efc612a8;
  • exact parent→child comparison: ahead-only, zero behind, exact parent as merge base, eight changed paths;
  • state: Draft and mechanically mergeable.

Any parent/head movement invalidates this ancestry statement until freshly reconciled.

Durable decision contract

  • billing_stripe_entitlement_decisions is append-only audit history with evaluated Subscription/Invoice observations, previous-decision link, action/reason, exact resulting claim provenance, and bounded evaluation/recording times;
  • billing_stripe_entitlement_claim_heads stores one current decision pointer per Stripe Subscription and is not an authorization token;
  • organization identity remains normalized through Subscription → Customer → organization instead of being duplicated in decision rows;
  • callers cannot choose stale evidence IDs: the repository selects the highest accepted Subscription observation and current Invoice observation for latest_invoice_id inside the transaction;
  • expectedPreviousDecisionId is an optimistic compare-and-swap token; mismatch returns a stable conflict rather than last-writer-wins history;
  • policy output is independently validated against exact tenant/Subscription and durable source observations;
  • retained prior paid access preserves the exact historical Invoice observation that still supports the claim even when current Subscription evidence has no Invoice; and
  • decision append plus current-head advance share one savepoint with rollback-confirm-before-release causal-error preservation.

server/db.mjs installs the schema at bootstrap after Subscription/Invoice evidence schemas and creates the production repository with deriveStripeSubscriptionEntitlement; request handlers do not create billing schema.

Claim-head tenant-integrity repair

Fresh source review found that the previous schema independently referenced claim_heads.subscription_id and claim_heads.decision_id without proving that the pointed decision belonged to the same Subscription. A schema-valid mismatched head could therefore bind one Subscription identity to another Subscription's entitlement decision; downstream effective-plan reads could consume the mismatched entitled value.

TDD repair:

  • test-only head bb3d90ca02c5191025cb0039a903c3b845c8f71b added a realistic in-memory SQLite regression that creates decisions for two Subscriptions and requires a cross-Subscription head rebind to fail while a same-Subscription advance succeeds;
  • production head c176efda6abbd3796fab776484422bb8efc612a8 adds a composite candidate key UNIQUE(subscription_id, decision_id) to decisions and a composite foreign key from claim heads to that exact pair;
  • a focused Node DatabaseSync reproduction against the exact repaired DDL is GREEN: cross-Subscription rebind raises FOREIGN KEY constraint failed, leaves the original head intact, and same-Subscription advance succeeds;
  • the integrity regression is imported by the existing claim package contract, so canonical normal-unit and c8 paths cannot silently omit it.

The effective parent→child diff remains bounded to the claim-ledger slice plus this focused integrity regression; no auth/session, Clearfolio, attachment, workflow, dependency lockfile, scanner suppression, or branch-protection artifact is changed.

Current exact-head evidence

Fresh repository-native workflows for exact head c176efda6abbd3796fab776484422bb8efc612a8 are queued and therefore non-passing:

  • Server Tests 32345673483;
  • Dependency Review 32345673484; and
  • OSV Scanner 32345673936.

There are no submitted reviews or review threads on this exact head. No predecessor-head, queued, absent, synthetic, status-only, author-only, or model-only evidence is treated as approval.

Scope boundary

This slice persists claim evidence only. It does not write orgs.plan, issue capabilities, change membership/RBAC, or apply a grant/revoke to any authorization path. #565 owns effective-plan application and now inherits this exact claim-head integrity repair; #568 owns buyer-visible billing status and likewise inherits it through #565.

Remain Draft. Do not integrate independently of #563 and its prerequisite stack. Exact-head deterministic/browser/coverage/security/dependency/supply-chain/review evidence must be regenerated on the unchanged final head before integration.

@coderabbitai

coderabbitai Bot commented Aug 19, 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: e4fdc2e0-3e8d-4dd0-beb5-a6cc6009e15c

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 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.

@seonghobae seonghobae added the enhancement New feature or request label Sep 7, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request 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