Skip to content

feat(billing): queue verified Stripe reconciliation triggers - #570

Draft
seonghobae wants to merge 16 commits into
feat/stripe-billing-authoritative-reconciliation-488from
feat/stripe-webhook-reconciliation-queue-488
Draft

feat(billing): queue verified Stripe reconciliation triggers#570
seonghobae wants to merge 16 commits into
feat/stripe-billing-authoritative-reconciliation-488from
feat/stripe-webhook-reconciliation-queue-488

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Buyer/reliability objective

Refs #488. Stripe may retry, duplicate, and deliver webhook events out of order, so a verified delivery must become durable reconciliation work, never inline lifecycle or entitlement authority. This stacked Draft turns already-verified Subscription/Invoice webhook evidence into one normalized pending trigger that #569 can later consume by re-reading current provider state.

Exact current stack

  • protected develop: 2dcbdc06d3a9e2f87eac42447338e7fcc523dd54;
  • exact parent/base feat(billing): reconcile Stripe state from current provider authority #569: feat/stripe-billing-authoritative-reconciliation-488@21e6a4acc8fd06ddebb0b2c35e45b504f417cc18;
  • exact contributor head: 8604c661eba3b5a5b97bea32eaa54bac4dcd2972;
  • fresh parent→child comparison: ahead 13, behind 0, exact parent as merge base, exactly six changed paths, +660/-4;
  • state: Draft and mechanically mergeable.

The effective semantic delta is limited to package.json, server/db.mjs, server/stripe_webhook_reconciliation_queue.mjs, tests/unit/coverage-script-contract.test.mjs, tests/unit/stripe-webhook-reconciliation-queue.test.mjs, and tests/unit/stripe-webhook-reconciliation-queue-integration.test.mjs. No auth/session, Clearfolio, general application route, dependency lockfile, workflow, scanner suppression, or branch-protection artifact is changed.

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

Implemented reconciliation-trigger contract

  • verified customer.subscription.* events map only to the exact bounded sub_... provider identity;
  • Invoice events support both current Stripe Basil parent.subscription_details.subscription provenance and the legacy top-level subscription representation, while contradictory representations fail closed;
  • irrelevant events and one-off Invoices retain verified evidence without manufacturing Subscription work;
  • billing_stripe_reconciliation_triggers stores one pending trigger per already-verified Stripe Event and references the immutable verified-event ledger by foreign key;
  • exact event redelivery is idempotent and does not require a fresh wall-clock read after durable queueing;
  • attempts to rebind one Event identity to a different Subscription fail closed;
  • unverified Event identities and malformed trigger/provider identifiers are rejected; and
  • this boundary performs no provider I/O, orgs.plan mutation, capability grant, or entitlement decision.

TDD and causal repairs

The original registered queue contract was intentionally RED while the production module was absent. Production implementation then established extraction, normalized schema, durable enqueue, bootstrap composition, and canonical c8/unit registration.

Fresh current-source verification exposed two additional causal defects and both were repaired test-first on this existing branch:

  1. Replay clock dependency. Exact durable redelivery still evaluated now() before checking the existing trigger, so a later bad wall-clock seam could fail an otherwise idempotent replay. The regression at predecessor 171a75cbe12590d492b03448ad41b1e83f390cdf made the second clock read invalid; 081f2a90211719af0f8c993f93d61f1c9ff267ee moved time acquisition to the first-insert path only.
  2. Split durability between event evidence and queue work. The production recorder committed verified Event/delivery evidence before opening the queue savepoint, so a queue-write failure could leave a relevant verified Event durable with no reconciliation trigger. Test-only 0bc93b447464ec9e3c4260fc715bf64f597cf2b1 injects a real SQLite BEFORE INSERT ... RAISE(ABORT) failure and requires zero surviving Event, delivery, and trigger rows. Current head 8604c661eba3b5a5b97bea32eaa54bac4dcd2972 wraps the existing nested repositories in one outer SQLite savepoint and releases only after both evidence recording and trigger creation succeed. Failed rollback remains fail-closed and cleanup errors cannot replace the causal failure.

The exact parent→child comparison remains bounded to the six intended queue/integration/evidence paths after both repairs.

Current exact-head evidence

Fresh repository-native workflows for exact contributor head 8604c661eba3b5a5b97bea32eaa54bac4dcd2972 exist but are still queued and therefore non-passing:

  • Server Tests 32375891058;
  • Dependency Review 32375891060; and
  • OSV Scanner 32375891523.

No submitted review or inline review thread exists on this exact head and no qualifying independent current-head approval exists. Queued, pending, skipped-required, cancelled, absent, neutral-required, failed, stale, predecessor, synthetic, status-only, author-only, or model-only evidence is non-passing.

Standards and scope boundary

The design follows Stripe's documented duplicate/retry and non-guaranteed-ordering webhook model: delivery creates bounded work; #569 remains responsible for authoritative Subscription/Invoice re-fetch and claim evaluation. Event arrival time and embedded snapshots are not lifecycle authority.

This PR does not yet implement worker claiming/completion state, retry/backoff/dead-letter policy, operator recovery, or the final end-to-end out-of-order convergence acceptance for #488. Remain Draft and do not integrate independently of #569/#568 and their prerequisite billing stack.

Merge gate

After prerequisite integration, reconcile this exact bounded semantic delta to the resulting protected head and regenerate every then-applicable exact-head deterministic/browser/statement/branch/function/line coverage/docstring/CodeQL/SAST/security/dependency/supply-chain/package/provenance/migration/recovery/resolved-thread and qualifying independent-review gate required by live policy. No predecessor-head, author-only, skipped, neutral, status-only, synthetic, or model-only evidence transfers.

@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: 5a0af606-ec6d-4c22-9e57-592867c1353d

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