diff options
Diffstat (limited to 'src/notify-text.js')
| -rw-r--r-- | src/notify-text.js | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/notify-text.js b/src/notify-text.js new file mode 100644 index 0000000..a88ab14 --- /dev/null +++ b/src/notify-text.js @@ -0,0 +1,79 @@ +// The words of every notification the worker shows while the app is closed. +// +// Chrome on Android (and, quietly, on desktop) scores each web notification's +// title and body with an on-device "unwanted notification" model before it +// shows it, and above 90 of 100 the notification is replaced by a "Possible +// spam" warning — hidden until the user taps "Show notification", and nine +// such in a week revoke the site's permission outright on a phone that +// doesn't visit much (Chromium kAutoRevokeSuspiciousNotification). Our old +// wording scored 92–99 across the board: "Payment received", "Incoming +// payment", "Payment request", "alice is calling", "New message", "alice +// sent you a message" — the exact shape of the scam notifications the model +// was trained (on synthetic data) to catch. What it lets through is less a +// rule than a measurement; the scores here come from Chrome 156's model via +// tools/notif-spam-score.js, which re-scores SAMPLES in a throwaway Chrome. +// Measured 2026-11-03: "sats" reads as money without reading as a payment +// scam (9–14), "payment" does not (95–97); a person's NAME in the body of a +// message or reaction line pushes it over (80–99), "New chat" / "<name>" +// does not (8–32); "reply" in any title is 96–99, "Someone replied" / +// "Open coinos to see it." is 13; a reply's TEXT is uncontrollable (an +// "@name" or a link in it scores 97+), so none rides along; "Calling" / +// "<name>" is 11–29 where every "<name> is calling" shape is 80–99. +// Re-run the scorer before changing any of these. + +export const OPEN = 'Open coinos to see it.'; + +function sats(n) { + const v = Number(n); + return v > 0 ? `+${v.toLocaleString()} sats. ${OPEN}` : OPEN; +} + +// A user-facing notification by reason. `d` is the push payload (amountSat, +// emoji) plus what the device adds (a sender's name). +export function notifyText(reason, d = {}) { + switch (reason) { + case 'payment': return ['Sats received', sats(d.amountSat)]; + case 'zap': return ['Zap received', sats(d.amountSat)]; + case 'dm': return ['New chat', d.name || 'Someone wrote to you']; + case 'chat': return ['New chat activity', 'There are new messages in your communities.']; + case 'mention': return [d.reply ? 'Someone replied' : 'You were mentioned', OPEN]; + case 'reaction': { + // a unicode emoji in the title is fine (17); a :shortcode: is not (85) + const e = d.emoji && !/^:[\w-]+:$/.test(d.emoji) ? ' ' + d.emoji : ''; + return ['New reaction' + e, `to your post. ${OPEN}`]; + } + case 'call': return ['Calling', d.name || 'Someone']; + // the wallet was asked for an invoice while closed (someone paying its name) + case 'incoming': return ['Someone is sending sats', 'Open coinos to receive them.']; + // a connected app asked the closed wallet to pay + case 'spend': return ['Spend request', 'A connected app asked to spend sats. Open coinos to approve.']; + default: return notifyText('chat'); + } +} + +// What tools/notif-spam-score.js scores: one line per shape a user can see. +export const SAMPLES = [ + notifyText('payment', { amountSat: 1000 }), + notifyText('payment', { amountSat: 21 }), + notifyText('payment'), + notifyText('zap', { amountSat: 1000 }), + notifyText('zap'), + notifyText('dm', { name: 'alice' }), + notifyText('dm', { name: 'Bitcoin Bob' }), + notifyText('dm', { name: 'Jarryd' }), + notifyText('dm'), + notifyText('chat'), + notifyText('mention'), + notifyText('mention', { reply: true }), + notifyText('reaction', { emoji: '❤️' }), + notifyText('reaction', { emoji: '🤙' }), + notifyText('reaction', { emoji: ':pepe:' }), + notifyText('call', { name: 'alice' }), + notifyText('call', { name: 'Bitcoin Bob' }), + notifyText('call', { name: 'Alice Caller' }), + notifyText('call'), + notifyText('incoming'), + notifyText('spend'), + ['Payment sent', '-1,000 sats via Damus'], + ['Spending balance', 'Receive or spend sats before 11/20/2026 to keep it alive.'], +]; |
