feat(billing): replace coupon with intro pricing and enable promo codes#1362
Merged
jeanduplessis merged 6 commits intomainfrom Mar 23, 2026
Merged
feat(billing): replace coupon with intro pricing and enable promo codes#1362jeanduplessis merged 6 commits intomainfrom
jeanduplessis merged 6 commits intomainfrom
Conversation
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (2 files)
Reviewed by gpt-5.4-20260305 · 275,297 tokens |
pandemicsyn
approved these changes
Mar 23, 2026
Replace the standard plan first-month coupon with an introductory Stripe Price and automatic schedule-based transition to the regular price. Enable allow_promotion_codes on all checkout sessions for Rewardful affiliate promo codes. Add switchPlan, cancelPlanSwitch flows, and a cron sweep to repair stranded intro-price subscriptions.
…or handling - Validate attached auto-intro schedules have the expected 2-phase structure before reusing them. If only phase 1 exists (half-configured from a prior failed rewrite), repair by adding the regular-price phase 2. - Abort switchPlan when releasing a hidden non-auto schedule fails with a transient error, preventing the subsequent create from being rejected by Stripe (subscription still attached to old schedule). - Derive phase-1 price from the newly created schedule's current phase (which mirrors the subscription at create-time) instead of the earlier subscriptions.retrieve(), avoiding stale price if a schedule released at a billing boundary between the two calls.
…riting user plan switches - Re-throw non-race errors from subscriptionSchedules.create() instead of silently swallowing them, so transient Stripe failures surface to callers - Check scheduled_by before repairing auto-intro schedules to avoid overwriting user-initiated plan switches that reuse the same schedule
…le helpers, harden error paths - Export and reuse resolvePhasePrice in switchPlan instead of inline extraction - Extract createAutoIntroSchedule and handleAutoIntroCreateRace from ensureAutoIntroSchedule - Check validateOrRepairAutoIntroSchedule return value and log unrecoverable schedules - Make cancelPlanSwitch tolerant of already-terminated schedules - Remove trial_end tests that are no longer applicable
0694c27 to
a529c10
Compare
…witch behavior changes - Add items array to mock schedule phases so resolvePhasePrice can extract prices - Update cancelPlanSwitch test to expect success+clear instead of rejection on release failure - Fix expected error message in orphaned schedule release test
…anSwitch Reverts the change that cleared DB state when releaseScheduleIfActive returned false. Transient failures leave the schedule attached in Stripe, so clearing local state would create a divergence where the user can't cancel a switch that will still execute. Instead, adds 'completed' to isScheduleAlreadyInactive to handle that terminal state properly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
STRIPE_KILOCLAW_STANDARD_INTRO_PRICE_ID), enablingallow_promotion_codes: trueon all KiloClaw checkout sessions (both Standard and Commit plans). This unblocks Rewardful affiliate promo code entry, which was previously blocked by Stripe's mutual exclusivity betweendiscountsandallow_promotion_codes.ensureAutoIntroScheduleidempotent helper creates a 2-phase Stripe subscription schedule (intro → regular standard price) withend_behavior: 'release', called fromsubscription.createdwebhook, reactivation, and cancel-plan-switch flows. Auto schedules are tagged withmetadata.origin: 'auto-intro'to distinguish them from user-initiated plan switches.Verification
pnpm typecheck— passed (all packages)pnpm jest src/routers/kiloclaw-billing-router.test.ts— 42 tests passedpnpm run format:check— passedpnpm run lint— passed (0 warnings, 0 errors)Visual Changes
N/A
Reviewer Notes
STRIPE_KILOCLAW_STANDARD_INTRO_PRICE_ID. After deploy,STRIPE_KILOCLAW_STANDARD_FIRST_MONTH_COUPON_IDcan be removed from environment.ensureAutoIntroScheduleuses a live Stripe fetch as single source of truth — it never trusts stale webhook payloads or DB state for schedule decisions. Race guards handle concurrent schedule creation. Partial failures are tolerated: the cron sweep (sweep 5) repairs stranded subscriptions on subsequent runs.ascasts minimized: Stripe schedule/price references usetypeofchecks with.idfallback instead ofas stringcasts, per coding style rules.discountsfrom the current phase.