max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
1 file changed,
+26 insertions,
-15 deletions
| @@ -21,7 +21,14 @@ | |||
| 21 | 21 | pub const ANNUAL_MULTIPLIER: i64 = 10; | |
| 22 | 22 | ||
| 23 | 23 | /// Minimum and maximum storage caps the user may pick. | |
| 24 | - | pub const MIN_CAP_BYTES: i64 = 10 * 1024 * 1024 * 1024; // 10 GiB | |
| 24 | + | /// | |
| 25 | + | /// The floor is where `MIN_CHARGE_CENTS` stops binding: 250 GiB x 0.8c is | |
| 26 | + | /// exactly $2.00, so every cap below it costs the same $2.00 for less storage | |
| 27 | + | /// and is strictly dominated. Offering that range asks the user to choose | |
| 28 | + | /// against their own interest. Raised from 10 GiB on 2026-08-21, when prod | |
| 29 | + | /// carried no SyncKit subscriptions at all, so nothing needed grandfathering. | |
| 30 | + | /// Should the floor or the rate move, this constant moves with them. | |
| 31 | + | pub const MIN_CAP_BYTES: i64 = 250 * 1024 * 1024 * 1024; // 250 GiB | |
| 25 | 32 | pub const MAX_CAP_BYTES: i64 = 10 * 1024 * 1024 * 1024 * 1024; // 10 TiB | |
| 26 | 33 | ||
| 27 | 34 | /// Billing interval for a SyncKit app subscription. | |
| @@ -94,22 +101,26 @@ | |||
| 94 | 101 | ||
| 95 | 102 | #[test] | |
| 96 | 103 | fn minimum_cap_hits_floor() { | |
| 97 | - | let price = quote_price_cents(gb(10), SyncBillingInterval::Monthly).unwrap(); | |
| 104 | + | // 250 GiB x $0.008 = $2.00, exactly the floor: the cheapest cap on | |
| 105 | + | // offer is also the last one the floor sets the price for. | |
| 106 | + | let price = quote_price_cents(MIN_CAP_BYTES, SyncBillingInterval::Monthly).unwrap(); | |
| 98 | 107 | assert_eq!(price, MIN_CHARGE_CENTS); | |
| 99 | 108 | } | |
| 100 | 109 | ||
| 101 | 110 | #[test] | |
| 102 | - | fn small_cap_uses_floor_until_breakeven() { | |
| 103 | - | // 100 GB × $0.008 = $0.80 → below the $2 floor. | |
| 104 | - | let price = quote_price_cents(gb(100), SyncBillingInterval::Monthly).unwrap(); | |
| 105 | - | assert_eq!(price, MIN_CHARGE_CENTS); | |
| 106 | - | } | |
| 107 | - | ||
| 108 | - | #[test] | |
| 109 | - | fn breakeven_around_250gb() { | |
| 110 | - | // 250 GB × $0.008 = $2.00 → equal to floor; storage formula starts taking over. | |
| 111 | - | let price = quote_price_cents(gb(250), SyncBillingInterval::Monthly).unwrap(); | |
| 112 | - | assert_eq!(price, 200); | |
| 111 | + | fn no_cap_on_offer_is_dominated_by_a_larger_one() { | |
| 112 | + | // Why MIN_CAP_BYTES sits at 250 GiB rather than lower: below the | |
| 113 | + | // break-even the floor binds, so a smaller cap buys less storage for | |
| 114 | + | // the same money. Nothing quotable may be priced at the floor except | |
| 115 | + | // the minimum itself. If the rate or the floor moves, this fails and | |
| 116 | + | // MIN_CAP_BYTES is what needs recomputing. | |
| 117 | + | for cap_gib in [251, 300, 512, 1024] { | |
| 118 | + | let price = quote_price_cents(gb(cap_gib), SyncBillingInterval::Monthly).unwrap(); | |
| 119 | + | assert!( | |
| 120 | + | price > MIN_CHARGE_CENTS, | |
| 121 | + | "{cap_gib} GiB still quotes at the floor, so caps below it are dominated" | |
| 122 | + | ); | |
| 123 | + | } | |
| 113 | 124 | } | |
| 114 | 125 | ||
| 115 | 126 | #[test] | |
| @@ -128,7 +139,7 @@ | |||
| 128 | 139 | ||
| 129 | 140 | #[test] | |
| 130 | 141 | fn below_minimum_cap_rejected() { | |
| 131 | - | assert!(quote_price_cents(gb(5), SyncBillingInterval::Monthly).is_err()); | |
| 142 | + | assert!(quote_price_cents(gb(200), SyncBillingInterval::Monthly).is_err()); | |
| 132 | 143 | } | |
| 133 | 144 | ||
| 134 | 145 | #[test] | |
| @@ -142,7 +153,7 @@ | |||
| 142 | 153 | // on either bound, or a `MAX_CAP_BYTES` that means something other than | |
| 143 | 154 | // 10 TiB, still rejects it. These sit on the two edges instead. | |
| 144 | 155 | assert_eq!(MAX_CAP_BYTES, gb(10 * 1024), "10 TiB, in bytes"); | |
| 145 | - | assert_eq!(MIN_CAP_BYTES, gb(10), "10 GiB, in bytes"); | |
| 156 | + | assert_eq!(MIN_CAP_BYTES, gb(250), "250 GiB, in bytes"); | |
| 146 | 157 | assert!(quote_price_cents(MAX_CAP_BYTES, SyncBillingInterval::Monthly).is_ok()); | |
| 147 | 158 | assert!(quote_price_cents(MAX_CAP_BYTES + 1, SyncBillingInterval::Monthly).is_err()); | |
| 148 | 159 | assert!(quote_price_cents(MIN_CAP_BYTES, SyncBillingInterval::Monthly).is_ok()); |