v2026.07.20.2
What's Changed
Internal
- Allow 14-digit Uruguay bank account numbers (BROU) by @gumclaw in #5981
- Widen HK/SG/TH/KR bank account number caps to match Stripe by @gumclaw in #5982
- Fix RecordNotUnique race in UTM link auto-creation (retry once) by @gumclaw in #5983
- Render dashboard preview panes inside medium-matching chrome (browser for web, email for emails) by @gumclaw in #5888
- Retry moderation text-only when OpenAI rejects an image URL (Faraday::BadRequestError invalid_image_url) by @gumclaw in #5984
- Fix FloatDomainError: NaN in AssetPreview#display_height (API v2 product serialization) by @gumclaw in #5978
- Stop error-notifying for connected accounts' own dispute events (kills Sentry GUMROAD-2 residual noise) by @gumclaw in #5987
- Fix NoMethodError in AffiliateMailer#direct_affiliate_invitation when affiliate or products are deleted by @gumclaw in #5988
- Retry UTM link auto-creation race when it surfaces as RecordInvalid by @gumclaw in #5986
- Stop alerting Sentry on expected bank-account rejections during Stripe account creation by @gumclaw in #5991
- Require 7-8 digit Japanese bank account numbers to match Stripe by @gumclaw in #5990
- Revert "Require 7-8 digit Japanese bank account numbers to match Stripe" (#5990) by @gumclaw in #5993
- Document why Japan bank account number minimum stays at 4 digits by @gumclaw in #5995
- Add product-level refund policy params to API v2 products create/update by @gumclaw in #6001
- Document product-level refund policy params in API v2 reference by @gumclaw in #6003
- Reschedule SSL certificate jobs on Let's Encrypt Acme::Client::Error::RateLimited instead of exhausting retries by @gumclaw in #5997
- Rescue Rack::Multipart::EmptyContentError in params-touching Rack::Attack throttles by @gumclaw in #6004
- Restyle analytics projected end-of-day overlay as a small dotted tick by @gumclaw in #6002
- Fix NoMethodError (undefined method 'external_id' for nil) in CustomerMailer#grouped_receipt by @gumclaw in #6007
- Stop paging Sentry when all images fail moderation but text was moderated (ClassifierStrategy noise) by @gumclaw in #6000
- Discard ActiveStorage::PreviewImageJob on ActiveStorage::PreviewError by @gumclaw in #6005
- Update analytics help article for restyled projection tick by @gumclaw in #6010
- Grant fullscreen permission to embed iframes at sanitize time by @gumclaw in #6012
- Fix N+1 email_infos queries in mobile url_redirect_attributes by @gumclaw in #5985
- Fix Slow DB Query in Products::AffiliatedController#index by counting products in SQL by @gumclaw in #6023
- Fix UnsafeRedirectError for bare relative next paths in SafeRedirectPathService by @gumclaw in #6025
- Stop Sentry noise from expected out-of-range cart quantity/price validation failures by @gumclaw in #6026
- Allocate buyer-presentment amounts across multi-item single-seller carts by @gumclaw in #5923
- Fix N+1 refund SUM and media location queries in mobile purchases endpoints by @gumclaw in #5994
- Automate qa-media cleanup: weekly deletion of merged-PR review evidence by @gumclaw in #6016
- Handle 'No active Lifecycle Action found' ValidationError in SidekiqUtility shutdown by @gumclaw in #6033
- Fix ChargeProcessorInvalidRequestError noise: treat FX-quote settlement-currency rejection as expected USD fallback by @gumclaw in #5999
- Retry transient SMTP timeouts in mail delivery instead of reporting every attempt (Net::ReadTimeout) by @gumclaw in #6030
- Set CANNOT_PAY failure reason for missing Stripe capabilities error in payout internal transfer by @gumclaw in #6029
- Fix unhandled Link::LinkInvalid 500 when price exceeds maximum in LinksController#create by @gumclaw in #6018
- Use correct PayPal brand casing everywhere by @gumclaw in #6022
- Stop alerting Sentry on expected bank-directory rejections during bank account sync (Stripe::InvalidRequestError) by @gumclaw in #6014
- Fix StateMachines::InvalidTransition (failed → processing) in Payouts.create_payment by @gumclaw in #6031
- Skip doomed FX-quote calls for merchant accounts with known non-USD settlement by @gumclaw in #6034
- Fix Errno::ENOENT crash during product publish (content moderation variant generation) by @gumclaw in #6037
- Filter Sentry noise from ad-hoc stdin rails runner scripts (GUMROAD-80 NoMethodError) by @gumclaw in #6035
- Fix Rack::Timeout crashes on sales API page_key pagination by adding a query timeout guard by @gumclaw in #6039
- Retry streamed store-agent tool calls whose JSON arrives corrupted (Ai::AnthropicClient::Error: unreadable tool call) by @gumclaw in #6038
- Fix ActiveRecord::StatementInvalid when license verify receives non-scalar params by @gumclaw in #6042
- Fix flaky Price.alive spec: stray live prices leak from non-transactional concurrency spec by @gumclaw in #6045
Full Changelog: v2026.07.20.1...v2026.07.20.2