CTA line now reads "Join the RM Circle team build 👉" and hashtags lead
with #RMCircle #CryptoTeamBuild. All templates verified <=280 (longest
270). Branding is in every tweet, not just implied by a hashtag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blotato counts the raw URL length toward the 280 limit (no t.co
shortening), so the long UTM CTA overflowed. Shortened default CTA to
?utm_source=x and added a guard in render(): drop hashtags, then trim
body, so a tweet can never exceed 280. Verified a real test post to
@cryptoteambuild returns HTTP 201.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New tweet.js posts a tweet to X via Blotato each time the indexer emits
a NEW team payout. Org-gated to the #21 organization; fires on all
payout types. Ships DISABLED (config.tweetEnabled default off / env
TWEET_ON_PAYOUT), so nothing posts until explicitly turned on.
Safety: dedupes by tx key (persisted to DATA_DIR/tweeted-payouts.json)
so restarts never re-post; a min-gap queue keeps bursts under Blotato's
30/min limit; API key read from env BLOTATO_API_KEY or DATA_DIR key
file, never committed or logged. Varied emoji/hashtag templates with a
CTA (+UTM) to the main page; deterministic template pick avoids X
duplicate-content rejection. Admin config allowlist gains tweetEnabled,
tweetCtaUrl, tweetHashtags, blotatoTwitterId.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>