Skip to content

v0.6.0

Latest

Choose a tag to compare

@rameerez rameerez released this 23 Jun 02:37
c321316

profitable v0.6.0 is an accuracy-focused production release for the Pay-powered metric layer. Every metric was re-audited against the data Pay 7.x-11.x actually stores, with regression coverage for the bugs found along the way.

This release intentionally changes user-visible numbers where previous calculations were wrong. Apps with meaningful trial volume, paused subscriptions, SQLite charge payloads, or Braintree/Lemon Squeezy subscription statuses should review the behavior notes below.

Highlights

  • Canceled trials that never converted no longer count as subscribers, customers, new MRR, churned MRR, churn, or dashboard summary activity.
  • Monthly churn rates no longer suffer from survivor bias: denominators now include subscribers who churn later inside the reporting window.
  • Monthly and daily summaries no longer count future trial conversions before they actually happen.
  • SQLite charge filtering now treats JSON booleans consistently with PostgreSQL/MySQL, so paid: false charges do not count as revenue on SQLite.
  • Pay 7-9 data-only charge schemas are supported again; revenue queries no longer reference pay_charges.object unless that column exists.
  • Processor status handling is stricter: expired now churns at ends_at, and pending is never billable.
  • Paused subscriptions now preserve their historical subscriber/customer lifecycle while staying out of current MRR when paused.
  • Profitable.time_to_next_mrr_milestone now returns a Profitable::NumericResult, so the documented .to_readable API works.
  • Added Profitable.mrr_at(date) as the public historical MRR snapshot API.

Metric Correctness Fixes

  • Fixed canceled trials polluting total_subscribers, total_customers, new_customers, new_subscribers, new_mrr, churned_customers, churned_mrr, churn, monthly_summary, and daily_summary.
  • Fixed churned subscriptions being removed from earlier monthly churn denominators when they churned mid-window.
  • Fixed future trial conversions appearing early in current-month/current-day summaries.
  • Fixed paid: false charge payloads being counted on SQLite because SQLite returns JSON booleans as 0/1 instead of text.
  • Fixed Pay 7-9 compatibility for apps whose pay_charges table only has data and not object.
  • Fixed paused lifecycle semantics so historical customer/subscriber counts and current MRR answer different questions correctly.
  • Fixed sub-dollar positive MRR being treated as “No MRR yet” in milestone messaging.
  • Fixed monthly churn denominator boundary behavior to match the inclusive period-start semantics used by churn.
  • Fixed existing Profitable::Error messages being double-wrapped during MRR snapshot delegation.

API And Documentation

  • Added Profitable.mrr_at(date) for historical MRR snapshots.
  • Kept raw calculate_mrr_at private so public metric methods consistently return Profitable::NumericResult.
  • Documented that Stripe is the only processor with subscription amount payloads stored locally by Pay out of the box.
  • Clarified that Braintree/Paddle subscriptions contribute 0 to amount-derived MRR metrics unless apps backfill processor subscription payloads into pay_subscriptions.object.
  • Corrected the stale README reference to Profitable.valuation_estimate.

Internal Cleanup

  • Consolidated churn-event queries into one helper.
  • Consolidated MRR “now” and MRR “at date” paths so current MRR and growth-rate snapshots cannot drift.
  • Centralized subscription payload lookup in Processors::Base.subscription_data.
  • Added schema-aware and memoized charge payload column detection.
  • Changed raw SQL subscription joins to Active Record association joins where appropriate.
  • Added direct delegate / actionview requirements and declared actionview as a gem dependency.
  • Removed the full top-level require "rails"; the gem now uses narrower direct dependency requires.

Behavior Notes

This release is expected to change metric outputs for some apps. These changes are corrections, not cosmetic formatting updates:

  • Trial-only cancellations disappear from paid subscriber/customer and churn metrics.
  • expired subscriptions no longer inflate active/billable metrics forever.
  • pending subscriptions no longer contribute to MRR-style or active subscriber metrics.
  • Paused subscriptions can still count historically after they became billable, but they are excluded from current MRR while paused.
  • Charge-based metrics are portable across Pay processors because Pay stores real charge amounts locally.
  • Amount-derived subscription metrics are fully supported out of the box for Stripe. Braintree/Paddle amount parsing requires local subscription payload backfills.

Verification

  • Default suite on the merged release commit: 338 runs, 520 assertions, 0 failures.
  • Local appraisal matrix green: Pay 7.3, 8.3, 9.0, 10.0, 11.0; Rails 7.2, 8.1.
  • GitHub Actions test matrix green across Ruby 3.3, 3.4, and 4.0 combinations.
  • Line coverage: ~97.75%; branch coverage: ~89.9%.
  • bundle exec rake build succeeds and builds pkg/profitable-0.6.0.gem locally.

GitHub Generated Notes

What's Changed

Full Changelog: v0.5.0...v0.6.0