Skip to main content

max / makenotwork

server: a soft monthly mail cap per creator, aligned to the billing period Max ruled the shape on 51eafe45: a soft maximum on total mails sent per creator per month, window aligned to the payment period, transparent, with an application path for increases. The commons it protects is the shared Postmark IP pool, where one creator's fan-out degrades delivery for everyone. Nothing bounded that before. resolve_audience caps one audience at 10,000 and last_broadcast_at allows one broadcast per 24 hours; neither bounds the count over a month, which is the number reputation follows. db::mail_caps owns the window, the counter and the reservation. Reserved up front for the whole audience: the decision has to be made before any mail leaves, and a per-mail increment would be 8,000 writes for one announcement and would leave a half-mailed list when it hit the cap mid-fan-out. The guard rides on the ON CONFLICT update, so two sends racing cannot both see room only one of them has. Four send paths gated: both announcement fan-outs and both broadcast handlers. A refused announcement emails the creator, because that path has no request left to answer and the mail is the whole of their notice; a silent throttle would read as the platform losing mail, which is worse than a refusal. The creator sees the count, the cap, the reset date and a warning band on the Creator Plan section, on the same gauge storage uses. An increase is a form with a reason, an operator queue at /admin/mail-caps, and a grant that writes the per-account override in the same transaction as the decision. The numbers are provisional and live in assumptions.toml, which is why the build did not wait on the pricing call in 7cf9e855: replacing them is an edit to that file and a restart. A test asserts every tier clears the worked example the decision names, so a number that would refuse ordinary work fails the build rather than a send. Out of scope, filed rather than dropped: feeding a list's complaint rate back into the cap.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-27 22:49 UTC
Signed with PGP, not checked
Commit: 44aa86830263b0b72f66e7ab66d5e5e2e11b0d65
Parent: c501687
24 files changed, +1369 insertions, -3 deletions
@@ -66,6 +66,16 @@
66 66 pub everything_total_bytes: i64,
67 67 // Founder cohort cap, display string with thousands separator ("1,000").
68 68 pub cohort_cap_display: String,
69 + // Monthly mail allowance per tier, and the allowance for a creator with no
70 + // active subscription. See `crate::db::mail_caps`; the numbers are
71 + // provisional pending the pricing call.
72 + pub basic_mail_cap: i64,
73 + pub small_files_mail_cap: i64,
74 + pub big_files_mail_cap: i64,
75 + pub everything_mail_cap: i64,
76 + pub no_subscription_mail_cap: i64,
77 + // Where the warning band starts, as a fraction of the effective cap.
78 + pub mail_cap_warn_at: f64,
69 79 }
70 80
71 81 impl TierPrices {
@@ -104,6 +114,12 @@
104 114 big_files_total_bytes: bytes_at(a, "tier_bytes.big_files_total"),
105 115 everything_total_bytes: bytes_at(a, "tier_bytes.everything_total"),
106 116 cohort_cap_display: str_at(a, "cohort.cap_display"),
117 + basic_mail_cap: bytes_at(a, "mail_cap.basic"),
118 + small_files_mail_cap: bytes_at(a, "mail_cap.small_files"),
119 + big_files_mail_cap: bytes_at(a, "mail_cap.big_files"),
120 + everything_mail_cap: bytes_at(a, "mail_cap.everything"),
121 + no_subscription_mail_cap: bytes_at(a, "mail_cap.no_subscription"),
122 + mail_cap_warn_at: float_at(a, "mail_cap.warn_at_fraction"),
107 123 }
108 124 }
109 125
@@ -129,6 +145,19 @@
129 145 }
130 146 }
131 147
148 + /// Monthly mail allowance for the given tier, before any per-account
149 + /// override. `None` is a creator with no active subscription, who still
150 + /// sends and gets the smaller unsubscribed allowance.
151 + pub fn monthly_mail_cap_for(&self, tier: Option<CreatorTier>) -> i64 {
152 + match tier {
153 + None => self.no_subscription_mail_cap,
154 + Some(CreatorTier::Basic) => self.basic_mail_cap,
155 + Some(CreatorTier::SmallFiles) => self.small_files_mail_cap,
156 + Some(CreatorTier::BigFiles) => self.big_files_mail_cap,
157 + Some(CreatorTier::Everything) => self.everything_mail_cap,
158 + }
159 + }
160 +
132 161 /// Total storage byte cap for the given tier.
133 162 pub fn max_storage_bytes_for(&self, tier: CreatorTier) -> i64 {
134 163 match tier {
@@ -302,6 +331,15 @@
302 331 }
303 332 }
304 333
334 + fn float_at(a: &Assumptions, key: &str) -> f64 {
335 + match a.get(key) {
336 + Some(LookupValue::Float(x)) => *x,
337 + // A ratio written as `1` rather than `1.0` is still a ratio.
338 + Some(LookupValue::Int(n)) => *n as f64,
339 + other => panic!("expected number at {key}, got {other:?}"),
340 + }
341 + }
342 +
305 343 fn str_at(a: &Assumptions, key: &str) -> String {
306 344 match a.get(key) {
307 345 Some(LookupValue::String(s)) => s.clone(),
@@ -99,6 +99,31 @@
99 99 recipients_per_send_display = "10,000"
100 100
101 101
102 + # ─── Monthly mail cap (canonical: src/db/mail_caps.rs) ───────────────────
103 + # A soft maximum on total mails one creator sends per billing month, protecting
104 + # the shared Postmark IP pool from one creator's fan-out. Soft: the creator sees
105 + # the count, is warned before the cap, and is refused with a message rather than
106 + # throttled silently. An increase is granted per account on application.
107 + #
108 + # PROVISIONAL. These numbers are placeholders that clear the stated bias --
109 + # a 2,000-person list mailed weekly is 8,000 a month and must be uneventful at
110 + # every tier -- and they are not the priced answer. The real ones are being
111 + # decided against what the tiers cost in GoingsOn mnw-server 7cf9e855. That is
112 + # why they live here: replacing them is an edit to this file and a restart.
113 + [mail_cap]
114 + basic = 25000
115 + small_files = 25000
116 + big_files = 25000
117 + everything = 25000
118 + # A creator with no active subscription still sends: announcements go out from a
119 + # project whether or not the tier subscription lapsed. Lower, because there is no
120 + # revenue behind it, and above any honest use of a free account.
121 + no_subscription = 5000
122 + # Where the warning band starts, as a fraction of the effective cap. A ratio
123 + # rather than a fixed remainder so a raised cap warns proportionally.
124 + warn_at_fraction = 0.8
125 +
126 +
102 127 # ─── Fan+ (canonical: fan-plus.md) ───────────────────────────────────────
103 128 [fan_plus]
104 129 monthly_price_usd = 8
@@ -40,6 +40,7 @@
40 40 pub mod items;
41 41 pub mod license_keys;
42 42 pub mod lists;
43 + pub mod mail_caps; // pub so the integration test crate can drive reserve/grant against a live pool
43 44 pub mod mailing_lists;
44 45 pub(crate) mod media_files;
45 46 mod models;