380 Commits

Author SHA1 Message Date
martbost 3d4b07a8ab Real cover art, and a third milestone destination
The cover was a drawn arc and a hoop I built out of rectangles. It looked like
it. Replaced with a kie.ai generated photograph, a basketball sitting untouched
on a wet floodlit court at night with the hoop in shadow behind it, which is the
whole argument of the post in one frame. The type is still set here rather than
prompted, because image models cannot letter.

Milestones and the daily snapshot now post to three places instead of two: the
main Crypto Team Build group, the InstantAdPay support topic (634443) and the
shared payments topic. The RM Circle proof channel is deliberately excluded,
that channel is RM Circle only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 08:07:09 -05:00
martbost 78892421bb Blog cover: the shot that lands short
Cover for "You Miss One Hundred Percent of the Ads You Never Run". The arc is
the argument: a shot that rises, falls and stops short of the rim, next to the
73,181 credits our members are holding and have never spent on an ad.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 07:58:51 -05:00
martbost 869eee809e Milestones post a card, and a dead target stops being silent
The 600-member milestone went out as plain text into the shared payments topic
and Marty scrolled straight past it. Every hundred now posts a picture.

The cards are pre-rendered for the whole ladder (600 through 10,000) and carry
no live figures on purpose: a number baked into an image rendered weeks early is
wrong by the time the mark is reached, so the numbers stay in the caption. The
send falls back to plain text if the card for a mark is missing or the caption
runs past Telegram's 1024.

Separately: a target listed in snapshotTargets with no chat id was skipped
without a word, so the "feed" half of every milestone and every daily snapshot
has been going nowhere for weeks while the log said it sent. It now warns.
telegramChatId is still unset, so feed is still dark until Marty says where it
should point, but at least it says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 07:45:27 -05:00
martbost 6ff21f76ee P&L: account for money the chain cannot explain
The P&L took revenue from AdminPaid events and holdings from eth_getBalance,
so anything else moving through a receiver was invisible. Receiver A has earned
10,871.89 POL and holds 4,561.19; nothing explained the difference, and the gap
would have widened every time Marty drew from it. "Why would I ever keep a
receiver wallet that I never take anything out of? That's stupid, so I need to
be able to account for it."

Three kinds, because three different things move through that wallet and only
one is profit. Revenue is outside income, a ClickBaitPays withdrawal paid in
POL, and counts toward profit. A draw is house profit spent on something, such
as funding RM Circle #139's Culmen to Apex upgrade; it leaves the wallet but is
not a cost of running InstantAdPay. A transfer is Marty's own capital parked in
the Tangem receiver for safekeeping, and moves the balance only: counting it as
revenue would report his savings as earnings.

The pane now states earned, plus revenue, less draws, against what is actually
held, and names any unexplained drift rather than hiding it in a balance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 18:10:56 -05:00
martbost 8656f7ce4d Admin members: resolve sponsors against every account, not the page's 500
The Members page loads the newest 500 accounts and built its sponsor name
lookup from that same list. Once the site passed 500 accounts every sponsor who
joined before that window became unfindable, so the page labelled them "dead
link: <name>" with a tooltip saying the member would fall into the holding
tank. It was doing that to 144 of the 500 rows, including cryptoassets 76
times, and not one token on the whole site is genuinely unresolvable.

Sponsorship itself was never affected: assignment at purchase time looks each
token up directly rather than scanning a list.

accounts.identities() returns the identity columns for every account with no
limit, which stays cheap at any size, and the page uses that for the lookup
while still showing 500 rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 11:25:38 -05:00
martbost 5c08be1c30 Campaign actions: a centred, even stack with a squarer corner
The column is narrow so these buttons stack. Left-aligned pills of different
widths read as a ragged edge, and a label that wraps inside a 999px radius
becomes a tall oval, which is what "Buy more views" was doing.

They are now centred, the same width, and cornered at 10px, so each label sits
on one line. Scoped to this table: everything else keeps the pill. The phone
card shares a row rather than stacking, as it did before, so that layout is
left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 09:10:50 -05:00
martbost 02d60d6ee1 Archive button: it had no text colour, and no room beside its neighbours
I gave it the class "ghost", which on PolHunter is a button and here is the
giant faded wordmark in the footer. That class sets color:transparent, so the
label was not dark, it was invisible. It now uses a new "quiet" variant, grey
on a muted outline, which reads clearly and sits below the mint actions rather
than competing with them.

The campaign actions also had no spacing on desktop. The mobile layout already
gapped them; the wide one leaned on a plain space between tags, so they sat
flush against each other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 08:57:56 -05:00
martbost f0a6a93f8b Campaigns: archive a finished one, get the credits back, keep the numbers
A member asked for a delete button. Deleting would orphan the credit ledger,
the hourly view rows and the P&L, and throw away the figures they actually
want, so a campaign is archived instead: out of the working table, listed in
full underneath with its views, clicks and spend, and restorable.

The credits are the real point. Reserved budget is computed from campaigns
that are active or paused, so a paused campaign quietly holds credits the
member cannot spend anywhere else. Archiving releases them the moment the
status changes, with nothing to refund and nothing that can double-refund.

Only a paused or finished campaign can be archived, so pause stays the
deliberate first step, and restoring brings it back paused rather than live.
The syndication rails are stopped on the way in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 08:40:17 -05:00
martbost 891eac1626 Overview: the PolHunter return card goes first
Marty's call: someone arriving from PolHunter stays on the dashboard rather
than being bounced back, because that is where the business is. That makes the
return card their only way back, and it was sitting third, below the launch
announcement for the site they had just come from and the Friday promotion.

It is hidden for everyone who did not arrive that way, so no other member's
page changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 06:35:33 -05:00
martbost 489d832546 Sign-in: stop telling a fast returning member off for being fast
The email-code endpoint refuses a request that arrives within two seconds of
the page loading, because a script fills a form instantly and a person does
not. A member whose email is already filled in by the browser has nothing to
type, taps straight away, and gets "Give the page a second, then tap again."

The page now waits out the remainder itself and sends when the window has
passed, so the person sees the normal sending state instead of an error.
The server check is untouched, so anything posting at the endpoint without a
page behind it still fails exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 05:50:34 -05:00
martbost 286ac9207a Hand the sponsor to PolHunter, and put its payouts in the P&L
PolHunter now pays a bounty when a hunter brings someone who turns up and
hunts, and the person who gets it has to be the one that member actually
joined under here. The sign-in payload carries sponsorRef and the join date
across so PolHunter is never guessing from a cookie.

Its payouts are real POL from its own faucet and none of it passes through the
ad contract, so the P&L could not derive it. It now reads the figures across,
cached and fail-soft, and shows finds, bounties and matches as their own card.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 04:36:02 -05:00
martbost ce9f3e6904 Videos: reject a source that does not load, and stop stranding the viewer
Michael Camire reported the video tab locking up after the fifth watch each
day. Three separate faults behind it.

A campaign could go live with a video address that resolves nowhere, because
the form only checked the shape of the URL. One has been sitting there since
11 September pointing at the example host, serving every Tier 1 member a black
player it could never finish. The create route now fetches the address and
refuses a host that does not answer, a 404, or a page that is not a video.

The Watch tab holds the landscape videos and Shorts holds the upright ones,
but they share one daily count. A member who cleared the tab was told to come
back tomorrow while clips were still waiting one tap away. When the other
surface still has something, the done screen now says so and links to it.

When a browser refused to autoplay, the button offered "Tap to play" but was
wired to fetch a different video, so the loaded one was thrown away and the
next also would not start. On a phone the clip could never be played at all.
The button now starts what is already loaded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 16:54:31 -05:00
martbost 68a92c39ff Milestones: a recorded mark stays done whatever its stamp
The done-check read the stored value, so a mark recorded as 0 counted as never
celebrated. Seeding the already-passed hundreds that way would have made the
site announce "400 members" to a channel watching 528. It now tests that the
mark is present at all. Caught before it posted; the live state has been
re-stamped either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 10:19:12 -05:00
martbost f255d096ad Milestones: celebrate every 100 members, not just the big marks
Marty, 2026-09-22. The ladder was 500 / 1000 / 2500 / 5000 / 10000, so most of
the year would pass with nothing to cheer. It is now every 100, with the fuller
write-up kept for the half-thousands and thousands and a short cheer in
between, so the small ones do not read as a repeated speech. Both are laid out
in short lines for a phone, like the daily snapshot. The hundreds already
passed are recorded as done on the live volume, so the next post is 600.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 10:15:02 -05:00
martbost 5c11bfa502 Daily snapshot: lay the numbers out so a phone can read them
The post was one paragraph per subject, and on a phone every line wrapped into
a block of text with nothing to catch the eye. It is now a heading and two or
three short lines per subject, with a blank line between, the date under the
title, and no line long enough to wrap on a narrow screen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 09:58:07 -05:00
martbost c47905d89a Overview announcements: let a member put one away for the session
The PolHunter launch card, the Five Dollar Friday card and the "you came from
PolHunter" card repeat on a timer, so anyone who has read one had no way to
clear it. Each now carries a small close control in its heading: the card
stays hidden for the rest of that browser session and comes back at the next
sign-in, so a message nobody acted on is never lost for good.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 06:29:49 -05:00
martbost 67fb8193bd Refill conversions: only count a genuine response. An unrelated ad already running is not a relaunch, and a still-running low campaign is not a conversion at all; adds a reset lever to re-decide verdicts
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 05:26:20 -05:00
martbost 635844a12b Campaign refill notices: tell an advertiser when an ad is nearly out and when it has stopped, one email per owner with what it delivered, their balance and the bonus ladder; every send recorded and watched for the relaunch, top-up or purchase that follows
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 05:21:57 -05:00
martbost 9df669fa7c Sponsor pre-check alert: only the checkout call may alert (the dashboard's display-only call never does), and the alert says what it is: a heads-up before the sale, nothing paid yet
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 10:55:09 -05:00
martbost a403ce3520 Promo tools > PolHunter: the two vertical spots with download, caption carrying the member's link, share buttons and the platform guide
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:59:58 -05:00
martbost 260daaf9d0 Viral links served in place, not redirected: Facebook follows redirects and og:url, so every share was losing the member's name; og:url now carries the ref, canonical stays clean; QA walk updated
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 08:07:12 -05:00
martbost c6c26b8073 PolHunter in the member menu from launch morning (the Overview reveal still waits for launchAt); Promo tools > PolHunter kit: share link, posts, swipe, banners, both videos; reveal card says tap to copy
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 07:36:37 -05:00
martbost e5cbecbdb2 Viral link builder: dropdown only (the paste box only ever accepted the site's own pages, which the dropdown already lists)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 06:13:25 -05:00
martbost 269247c871 Blog renderer: bump blog-page.js tag so articles load the viral-link bar now, not after the cache
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 05:56:21 -05:00
martbost e2f88dad42 Viral links: any public page + ?ref=<username|code|id> sets the same last-touch sponsor cookie as /join, counts under a 'page' hook in link stats, then redirects to the clean URL; Promo tools > Viral links builder (pages list + paste any address, copy + share); blog posts show a signed-in member's own link; chatbot answer; QA walk proves redirect + cookie
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 05:54:55 -05:00
martbost 337d5dd556 Walk-up feed post moves to the activation event (a member who activates first and buys later was never posted); the Purchase branch no longer posts it
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:41:11 -05:00
martbost 6f5b5dbae6 Earning guide: adds the POL side (50/20/10 split, payouts on, qualification at 2 and 5, pass-ups, sponsor lock, where to see it); title and meta cover both kinds of earning
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:27:27 -05:00
martbost 91456ae0ce Promo tools: Five Dollar Friday banner set (1200x630, 1080x1080, 728x90, 300x250)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 14:06:16 -05:00
martbost 68b08ab8cc Five Dollar Friday: +20% purchased-grade credits on any $5+ package bought on a Friday (Central), live wave on the landing strip and Overview card, Telegram every ten packs + Friday kickoff + midnight wrap-up, Thursday notice + email, Five Fridays badge, promo posts + swipe, chatbot; first Friday 2026-09-25
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 13:59:15 -05:00
Marty Bostick de5bdfefaf SocialPix gate: /from/socialpix bridge page (advertiser copy by default, ?seg=earn), chatbot knows the new page
socialpix.club was being used as a free ad board by posting bots; its signup/onboarding/post flows
now redirect here. No legacy credits for these arrivals. Referrer tagging (traffic.js) already covers /from/*.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 09:26:40 -05:00
martbost 9fafd0bf43 Training: feature 'polhunter' entries appear at the launch moment; launch card links the feeder video
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 05:27:10 -05:00
martbost 9a531538ed Launch-day surprise: PolHunter card on the Overview and the menu entry appear at siteConfig.launchAt (self-flipping, nothing visible before)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 05:16:30 -05:00
martbost 7ea7a5f409 PolHunter return loop: ?from=polhunter sets iap.return (landing + join links), /api/me carries returnTo, Overview card sends them back once a wallet is linked, wallet link answers next=/api/my/polhunter, hand-off clears the cookie
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 20:00:55 -05:00
martbost ad539d5fae Ledger: a NAS zone under the payout feed (mission pages must carry ad inventory)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 16:40:07 -05:00
martbost 5fe3dfa625 Dashboard: PolHunter menu entry removed until it opens (the hand-off route and the ledger embed stay; neither is visible)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 16:15:26 -05:00
martbost 49a92461f0 CSP: put polhunter.com after 'self' in connect-src (the previous edit produced an invalid source list)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 14:26:43 -05:00
martbost 240a928323 CSP: connect-src allows polhunter.com so the PolHunter embed can fetch its code
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 14:23:57 -05:00
martbost af710f68b8 PolHunter hand-off, nav entry, and the ledger embed
/api/my/polhunter signs a member across to polhunter.com with a five-minute single-use HMAC
token (memberId, email, wallet, username); PolHunter has no sign-up and no mailer, this is the
only way in. A PolHunter entry in the dashboard nav. The PolHunter embed on the public ledger
with one slot beside the payout feed; CSP allows polhunter.com.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 14:20:16 -05:00
martbost 0d2621defd missed: list each tier's skips in walk order
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 13:16:03 -05:00
martbost c00ec64cf8 Missed-payout notice shows the whole chain, one message per purchase
Marty (2026-09-19): show every missed qualification so the whole chain is visible. The old
notice fired once per passed-up tier and showed only that tier. AdminPaid is the last event of
every purchase transaction (119 of 119 in the index), so the notice now fires there, gathers
every PassedUp and TierPaid of the tx, and missed.js composes one message: each tier's walk,
every person passed over with their buyer count, who finally caught it (or that the company
kept it), and the total POL that walked past how many people on that one sale.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 13:14:12 -05:00
martbost d90f08d54a Milestone posts: a celebratory Telegram post the moment membership crosses 500 (then 1k, 2.5k, 5k, 10k), once per mark
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 10:52:21 -05:00
martbost a85ee4cacf Login slots: 1,000 credits, at most 3 member slots live; viewer gets an open-in-tab link
Marty (2026-09-19): cap the login-ad slots. About 124 members sign in a day and every live
slot shares those views, so a fourth slot only thins the other three. Member slots only;
house login ads now step aside whenever a member slot is running (JSON: filtered out of the
pool; MySQL: ORDER BY house ASC). The 14 slots already running keep their term; new buys are
refused until one ends. Format label and chatbot updated.

mindfulmojo (email, 2026-09-19): the viewer frames the advertiser's page and both controls
meant "back"; some sites refuse to load inside a frame and signing up is easier in a full tab.
The viewer bar now carries "Open site in a new tab", set from the ad's target URL.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:46:12 -05:00
martbost f282e328b5 Snapshot: where the credits came from (handed out / earned / spent), last 24h
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:23:04 -05:00
martbost 415a5f3848 Partner-code credits arrive as a drip; unclaimed installments expire
Marty (2026-09-19): partner codes keep working with no monthly cap, but the credits stop
being a dump. A fifth is paid the day the code is redeemed, then a fifth on each day the
member finishes their daily ad set, five days in all, and whatever is unclaimed 30 days after
redemption is never paid. Same headline number for the partner to promote; paid only to
people who show up. 49 of the 52 PARTNER redemptions were still sitting on 500+ unspent.

Every redemption now records the site the ?promo= link was opened from (iap.promoref cookie
set from the Referer at link-open), so a code's traffic can be attributed to the partner page
it was supposed to come from. Member-funded codes charge the funder one installment at a
time; a short funder leaves the installment due, not lost.

Pre-drip redemptions were paid in full up front and are marked paid=credits at start-up, so
nothing is paid twice. Covered by a module test (13 checks: per-day cadence, gaps, rounding,
expiry, pre-drip rows, declined payer) and an end-to-end HTTP test on a local copy (9 checks).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 06:24:14 -05:00
martbost 5ebe890760 Paged lists: 25 rows, then a clearly marked next page
Marty (2026-09-19): once a membership gets large, My line and the other lists scroll forever.
One helper, pageList(), pages what each pane already renders: rows past the current page are
hidden and a solid-mint control bar (row range, Previous/Next 25, page count) goes under the
list. Row markup and bindings are untouched, so it goes on every growing list at once: My
line per level (the Activity drawer pages with its row, and a chip drill-down opens on the
right page), the Overview roster, the Campaigns table and its credit ledger, each Pipeline
column, and the Messages thread list. Asset tags bumped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 06:02:28 -05:00
martbost 70c4053201 Network Ad Space zone on the Faucet Wave and Tier One Ads landing pages
Marty asked for a NAS zone on the two legacy squeeze pages (2026-09-19). Injected server-side
in serveJoinPage for the fw-*/t1-* angles only, below the fine print and above the footer
links; the regular join pages stay ad-free. script-src now allows networkadspace.com, which
it did not, so the tag would otherwise have died silently under the CSP.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 05:50:02 -05:00
martbost 39572c0ff5 Sign-up deny list beside the allow list
fraud-allow.json says "never block this person". There was nothing for the opposite case.
fraud-block.json: an address on it cannot open an account through /api/signup or the
email-code door, and the admin fraud report carries the list with a matching
/api/admin/fraud/block route. Existing accounts are untouched; Suspend covers those.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 05:46:04 -05:00
martbost b061053ccf Daily rules run on Central time, and the sign-in bonus gets a hard floor
today() was a UTC day, which rolls over at 7 PM Central. Sign in at 6:55 PM and again at
7:05 PM and those were two different days, so the once-per-day sign-in bonus paid twice,
ten minutes apart. On the live ledger 83 of the first 364 sign-in bonuses landed less than
24 hours after the previous one, one pair 24 minutes apart, worth 618 credits.

The same boundary governs the daily-credit claim, the claim streak, each campaign's daily
spend cap and the login-ad daily meter, all of which could turn over twice in one Central
evening.

ctDay() puts every member-facing daily rule on America/Chicago, which tracks CST/CDT on its
own. Reporting slices elsewhere are left alone rather than re-bucketing chart history.

The bonus also records login_ts now and refuses to pay again inside 20 hours, whatever the
day string says. 20 rather than 24 so signing in at the same time each morning never skips.

Safe to deploy between midnight and 7 PM Central, when the two day strings agree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 05:19:44 -05:00
martbost 0a50d07658 Login ads become a flat 30-day slot
The daily meter charged 100 credits for every day a campaign was shown,
with no end date. It produced 74-day queues, and worse, each new campaign
added 100/day of charges while adding no inventory: on 18 September, 15
campaigns were charged 1,500 credits against a platform that had produced
367 login impressions in its entire life. That had stopped being a pricing
inefficiency and become members paying for delivery that did not exist.

Now: 3,000 credits buys 30 days of unlimited impressions, charged once at
purchase, with no delivery promise — the model Marty wanted, matching how
ClickBaitPays sells theirs. The price is deliberately identical to 30 days
at the old daily rate, so nobody pays more than before; they just get a
known end instead of an open-ended drain.

It reuses the `featured` shape, which was already a flat up-front buy that
runs to `expires`. Both daily meters — MySQL and JSON — now skip any
campaign with an expiry, so a slot can never be metered. The existing
sweep closes it on day 30 and returns anything unspent.

qa/login-slot.mjs, 9 checks, including that the slot price still equals
30 days at the old rate and that neither meter can touch a slot campaign.
Member walk clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 16:18:27 -05:00
martbost ccc372152d Sessions last 4 hours, and we say why
Marty's call. Sign-ins expired after 24 hours, which meant a member passed
the login gate roughly once a day — and that gate is the entire inventory
behind the login-ad product. The platform has served 356 login impressions
in its life while members have bought 20,526 credits of them.

Four hours, env-tunable via SESSION_TTL_HOURS.

Said out loud in three places rather than left to feel like a glitch:
the login gate itself now explains it, the chatbot has a canned answer for
"why do I keep getting logged out", and the same fact is in the assistant's
system prompt so the AI never calls it a bug. Wording throughout is
Marty's: to keep resources optimised we do not keep anyone signed in
longer than 4 hours, and nothing about the account, credits or line is
affected.

The canned pattern was checked against the neighbours it sits beside —
seven phrasings reach it, and withdraw / pyramid / earnings / second
account / payout answers are all untouched. CANNED is first-match-wins,
so that check matters.

Member walk clean, chatbot suite 35 green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 13:31:52 -05:00