diff --git a/snapshot.js b/snapshot.js index 97a2499..26520bc 100644 --- a/snapshot.js +++ b/snapshot.js @@ -112,16 +112,37 @@ async function tick() { async function preview() { const sc = X.siteConfig(); return compose(await gather(), sc.telegramCtaUrl); } -// ---- membership milestones (Marty, 2026-09-19): one celebratory post per mark, the moment it is crossed -const MILESTONES = [500, 1000, 2500, 5000, 10000]; +// ---- membership milestones: one celebratory post per mark, the moment it is crossed. +// Every 100 members since 2026-09-22 (Marty), with the fuller write-up saved for the round +// thousands and the half-thousands so the small ones stay a quick cheer, not a repeated speech. +const STEP = 100; +const isBig = m => m % 500 === 0; +const marksUpTo = count => { const out = []; for (let m = STEP; m <= count; m += STEP) out.push(m); return out; }; +const MILESTONES = marksUpTo(10000); // kept for callers that want the ladder + function composeMilestone(mark, s, cta) { - const L = []; - L.push('\u{1F389} ' + n(mark) + ' members on InstantAdPay.'); - L.push(n(mark) + ' people have joined, and here is what that looks like right now: ' + n(s.wallets) + ' wallets linked, ' + n(s.payoutsOn) + ' with payouts switched on, ' + n(s.lifeBuys) + ' purchases, and ' + pol(s.lifePaidWei) + ' POL paid to members in the same transactions the purchases came from. Every one of those payments is on the public ledger.'); - L.push('Thank you to every member who brought someone in. That is the whole engine, and it is working.'); - L.push('The next ' + n(mark) + ' start today.'); - L.push('Live ledger' + (cta ? ' \u00b7 Join free' : '')); - return L.join('\n\n'); + const ledger = 'Live ledger' + (cta ? ' \u00b7 Join free' : ''); + const B = []; + B.push('\u{1F389} ' + n(mark) + ' members on InstantAdPay'); + if (isBig(mark)) { + B.push(n(mark) + ' people have joined. Here is what that looks like right now:'); + B.push('' + n(s.wallets) + ' wallets linked\n' + + '' + n(s.payoutsOn) + ' with payouts switched on\n' + + '' + n(s.lifeBuys) + ' purchases\n' + + '' + pol(s.lifePaidWei) + ' POL paid to members\nin the same transactions'); + B.push('Every one of those payments is on the public ledger.'); + B.push('Thank you to every member who brought someone in. That is the whole engine, and it is working.'); + B.push('The next ' + n(mark) + ' start today.'); + } else { + B.push('Another hundred through the door.'); + B.push('' + n(s.wallets) + ' wallets linked\n' + + '' + n(s.payoutsOn) + ' with payouts on\n' + + '' + pol(s.lifePaidWei) + ' POL paid to members'); + B.push('Every payment on the public ledger.'); + B.push('Next stop: ' + n(mark + STEP) + '.'); + } + B.push(ledger); + return B.join('\n\n'); } async function memberCount() { if (!(X.db && X.db.enabled())) return 0; @@ -132,7 +153,7 @@ async function milestoneTick() { const sc = X.siteConfig(); if (!sc.telegramBotToken) return null; const st = state(); const done = st.milestones || {}; const count = await memberCount(); - const due = MILESTONES.filter(m => count >= m && !done[m]); + const due = marksUpTo(count).filter(m => !done[m]); if (!due.length) return null; const mark = due[due.length - 1]; const text = composeMilestone(mark, await gather(), sc.telegramCtaUrl); @@ -147,4 +168,4 @@ async function milestoneTick() { } async function previewMilestone(mark) { const sc = X.siteConfig(); return composeMilestone(Number(mark) || 500, await gather(), sc.telegramCtaUrl); } -module.exports = { init, gather, compose, post, tick, preview, milestoneTick, previewMilestone, memberCount, MILESTONES }; +module.exports = { init, gather, compose, post, tick, preview, milestoneTick, previewMilestone, composeMilestone, memberCount, MILESTONES, STEP };