Makes the depth-matched payment routing visible per member: walks their
subtree and shows who is ONE upgrade away from paying them (member at
depth D whose level equals D — their next upgrade routes to this
position first), the exact amounts from the contract's cost tables
(exposed via the member API), eligibility warnings (needs 2 directs /
needs level X), a ready-now total, and whether it covers their own next
upgrade. Members building toward their pay-you level are counted, with
the takeaway line "helping your leg upgrade IS your income."
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shareable page from the 2026-08-13 source review: code immutability
(no proxy/delegatecall/selfdestruct, Sourcify exact match), same-tx
distribution (no pooled funds), locked prices and fee constants, the
honest list of owner powers with the 50% entry-fee cap, where unmatched
pass-ups go, and verify-yourself links. Linked from all public footers,
the payment-proof note, and the chatbot (canned + AI prompt).
Also: passed-over lists now exclude structurally-skipped uplines — a
level-N payment never checks the first N-1 uplines, so listing them as
"not eligible" was misleading.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When a queue member's MemberUpgraded event lands, their Level in the
rotation queue updates automatically (same op as the admin dropdown),
with a Telegram note. Current queue trued up against the chain: four
entries corrected (30, 35, 46 up to Ascensus; 56 down to Scintilla —
it had been set optimistically).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The chain-only BFS pick could promote structurally-next but inactive
positions (#21's dashboard said #38 — not in the queue, likely inactive —
while the team rotation was working #36). Next-in-line now prefers the
active rotation sponsor when they're in the member's leg and unqualified,
then the first chain-order queue participant, falling back to the pure
structural pick for legs outside the queue.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A verified rotation join (@chriskelly8, ID 73 under #36) still required
a manual "add to queue" step from the Telegram message and got missed.
Rotation-path submissions now insert themselves into the sponsor queue
as waiting positions (name from the submission, level from chain,
parent = active sponsor, dedupe-guarded), and the Telegram alert reports
the queue position instead of asking for action. #73 was added manually
to catch up.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/my/<id> links circulate (address-bar shares, pre-/join links), and a
cold prospect landing there saw stats with no story. First-time viewers
of a position now get a banner: two-sentence RM Circle summary, a
"Read your invitation from this member" CTA into /join/<id>, a strategy
link, and the risk line. Hidden for repeat viewers of the same position
(likely the member) and dismissible per session.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prospects who clicked a member's shared /my link landed on a bare stats
dashboard with no explanation of the program. New /join/<id> page carries the
full bridge-page story (video, strategy, matrix, live on-chain payout proof)
personalized to one sponsor: their live position stats as proof, their ID
pinned on the dApp join button, and the submit-your-ID form locked to them
(source invite-<id>). Dashboard share buttons + QR codes now hand out the
invite page; /my stays the member dashboard. Invalid/unregistered invite ids
fall back to the /start rotation. Tracked as new 'join' event with an admin
traffic column.
Also: the chain indexer now auto-increments a rotation sponsor's directs when
a registration names them as referrer (same op as the admin ⊕), announcing it
on Telegram. At 2/2 it alerts to Qualify instead of auto-rotating — moving
the team focus stays a human decision.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two leg-build members submitted the /start form thinking it was required,
polluting rotation bookkeeping. Rather than two forms, the server now
classifies every submission by on-chain truth: referrer == active
rotation sponsor -> "rotation" (Telegram says +1 direct, add to queue);
anyone else -> "leg" (correct sponsor credited, "no rotation action
needed"). The member dashboard gains its own "Just joined under this
position?" form so leg builders have a proper landing spot; /start
feedback explains each path to the submitter; admin submissions table
shows a rotation/leg chip. Verified against live data: ID 65 claiming
sponsor 36 correctly classified leg under #62.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Marty's final framing: the teachable rule stays "get your 2, retire
your link, help your 2" — but a late signup on a qualified link is
presented everywhere as a welcome bonus (full entry reward + depth via
spillover), never a rule violation. Applied consistently across the
strategy page, start callout, chatbot (canned + AI prompt), training
article, and both share-card notes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the last "shallow legs" claim and reword "retires your link" —
a qualified link keeps working and spills depth; it just stops being
the team's focus.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old copy claimed qualified links must be retired to avoid "extra
shallow legs" — factually wrong for this contract: extra signups on a
qualified link spill DOWNWARD (BFS) as depth, and the referrer keeps
earning the full entry reward on every signup with no cap at 2. Updated
the strategy flow, team-principle notice, strategy card, start-page
callout, chatbot (canned + AI prompt), training article, and the
qualified share card: the team play is still helping your 2 get their 2
(only own directs qualify a position), but continued personal promotion
is accurately described as paid depth-building, and spillover recipients
earn only when the spilled member upgrades — if qualified and leveled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tail added new members but never updated the referrer's directCount,
the parent's matrix slots, or the recipient's earnedPol — so a member
who qualified mid-day kept showing 1/2 in tree views until the next
daily snapshot (hit live: #63 joined under #35 at 22:56 UTC and #35
still displayed unqualified). Registrations now increment the referrer's
count and wire the new member into the parent's l/r; payouts bump the
recipient's earnedPol. One-time re-snapshot on deploy trues up the
stale state.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Chat: new canned answer covering spillover keywords (why "2 under me
but 1/2 directs", pass-over eligibility) and the same facts added to
the AI system prompt so both chat modes answer consistently.
- Training: "Understanding spillover" article after the videos — what it
is, why it doesn't qualify you, why it still pays your position via
matrix upgrade payments, and the qualified+leveled eligibility rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per the contract's _payUpline rule, uplines are skipped for lacking 2
directs OR the required level — not level alone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tree nodes now carry referrerId, so positions placed by spillover (their
referrer differs from their matrix parent) get a teal "spillover · ref
#N" tag on cards in both the member dashboard and admin matrix, plus a
legend entry. When a member is unqualified but has spillover positions
under them — the classic "why do I have 2 under me but no checkmark?"
state — a callout explains that spillover grows the matrix but only
members joining with their own ID count toward 2/2, and points them at
their share link.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The RM logo + title in the nav now links back to / on the bridge,
start, training, and member-dashboard pages.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sessions now load from and save to sessions.json in the data volume
(0600, atomic write, expired entries pruned on save), so a redeploy no
longer logs the admin out. Verified: session cookie survives a full
server restart.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Instead of only pointing at the team rotator, a qualified member's share
card now runs the moving-link wave automatically: breadth-first,
left-to-right, the first position below them with fewer than 2 directs
becomes "next in line" — their QR, page link, and join CTA all carry
that position's ID. When it qualifies, the card rotates to the next one.
Falls back to the team rotator when the whole leg is qualified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- "Your team" now covers the member's FULL leg with click-to-drill
pyramid, breadcrumb, and a list-view toggle (mirrors the admin matrix).
- Legend under both the member tree and admin matrix explaining the
qualified checkmark, tier badges, and downline rollup.
- "Share this position" card: while under 2/2 it's a personal recruiting
tool — per-member QR (vendored qrcode-generator, CSP-safe), copy link,
and a join CTA carrying the member's ID as sponsor. At 2/2 the page
automatically retires the link and redirects sharing to the team
rotator, so personal referrals can't undermine the moving-link
strategy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Self-hosted SVG QR (CSP-safe) pointing at /start?utm_source=qr, so
scanned visits appear as their own "qr" source row in admin analytics.
Sits between the CTA and "See the Strategy" on mobile for the
show-your-phone recruiting flow; centered below the buttons on desktop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gold "★ Qualified" pill in the member-dashboard header (or an amber
"N more directs to qualify" pill), and a gold ✓ corner medallion on
every qualified position card in both the member tree and admin pyramid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Members enter their on-chain ID (or follow a /my/46-style link) and see
their own position: tier/level/directs/earnings facts, their subtree
pyramid with downline rollups and open slots, classified payment
history, and lineage to root — all chain-derived data only, none of the
admin operational config. Public endpoint /api/public/member is cached
(120s) and rate-limited (20/min/IP). Linked from the public footers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each tree node now carries a rollup of its subtree — members below and
their combined earned POL — shown as a footer line on pyramid cards and
inline in the list view.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The contract books income atLevel = the level the payer upgraded OUT of
(upgrade N->N+1 records atLevel=N), so an Ascensus upgrade pass-up was
displaying as "Scintilla". Income rows are now classified against the
contract's getAllCosts() tables — upgrade pass-ups arrive at full
upgrade cost, entry referral rewards at slot cost minus the 5% admin fee
— and display "Upgrade to Ascensus" / "Entry — Scintilla" in the admin
income table, public feed, and toasts. Stale snapshot rows re-classify
via a forced re-snapshot on boot.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The name in the Sponsor Queue is now a click-to-rename control (pencil
appears on hover), using the existing PATCH endpoint; server trims and
caps the name.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New config teamAlertEmail: the same team-gated on-chain events that post
to Telegram (registration, upgrade, payout at/below teamRootId) also go
to this address via SendGrid, so deep-leg activity surfaces even away
from Telegram.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both marketingwithmarty.com and mybrandedvoice.com are SendGrid
DKIM-authenticated; Marty's sending identity is marketingwithmarty.com,
so the default from and the admin label now reflect that.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the chain tail sees a payout to a member whose sponsor record has a
contact email, the site emails them the amount, source, and Polygonscan
link (plain text — deliverability). SendGrid key is pasted in a new
admin panel (stored in the data volume, like the OpenRouter key) or set
via SENDGRID_API_KEY. From address defaults to no-reply@mybrandedvoice.com
— the domain SendGrid is DKIM-authenticated for — and is editable in the
same panel. Not gated on teamRootId; any member with an email on file.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sponsors can carry an optional contact email (Add Sponsor form, ✉ inline
edit in the queue, shown under the name). New config teamRootId: any NEW
on-chain event at or below that member ID — registration, upgrade, or
payout seen by the live tail — posts to the Telegram group topic, with
the tx link and the sponsor's contact email when one is on file.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matrix View now defaults to a generation-by-generation pyramid (root + 3
generations of position cards, empty placements shown as dashed open
slots). Clicking a position re-roots the pyramid there; a breadcrumb
navigates back up. The collapsible list stays behind a toggle. Tree
payload now carries explicit left/right children so an only-child lands
on the correct side.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New chain.js reads the RM Circle contract (0x33Bd…2DAF, Polygon) via free
public RPCs — no API keys. Daily snapshot rebuilds complete payout history
from getIncomeHistory (log providers prune old history), and a 60s
eth_getLogs tail catches new payouts with tx hashes, upgrade context, and
passed-over upline IDs.
- Bridge page: "Live payment proof" feed + timed toast pop-ups for payouts
seen in the last 15 min, every row linking to Polygonscan.
- /start: same toasts; ID submissions are now verified against the contract
(result shown to the member, in Telegram notify, and in admin).
- Admin: on-chain member lookup (lineage to root, directs, matrix children,
full income history) and a collapsible full matrix tree view.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Framing was blocked site-wide (X-Frame-Options DENY + frame-ancestors
none), so safelists and traffic exchanges showed a blank panel. Public
pages now send frame-ancestors *; admin.html keeps the strict lockdown.
Join button opens the dApp in a new tab so it escapes the exchange
iframe (dApps typically refuse to render framed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Start page step 6 is now a bold gold-highlighted "Submit your NEW RM
Circle ID" form with larger step numbers throughout; captures the
sponsor the visitor was shown at join time.
- POST /api/public/submit-id: validates numeric ID, dedupes, stores on
the volume, records a per-source "purchase" analytics event, fires a
BeMob postback (txid=purchase-<clickid>) to close paid campaigns, and
posts the new ID + sponsor + source to the configured Telegram chat
(MB Hermes pattern). Rate-limited.
- Admin: Member ID Submissions table, "Confirmed joins" tile, and
Telegram bot token / chat ID settings.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- track.js stores ?clickid= (or ?cid=) for the session; rides through
bridge -> start navigation alongside the existing source attribution.
- Join click (the conversion) sends the clickid; server fires a
fire-and-forget S2S postback to the admin-configured BeMob postback
URL (cid + txid=join-<clickid>, payout 0) and counts successes per
source in analytics.
- New admin setting: BeMob postback URL (server-side only, not exposed
in public config).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Key is stored on the persistent volume (0600, never in git), read
dynamically per request, maskable status only in admin state, and
clearable to fall back to built-in answers. OPENROUTER_API_KEY env var
still takes precedence if ever set.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
POST /api/public/chat proxies to OpenRouter (model from
OPENROUTER_MODEL, default deepseek/deepseek-v4-flash:nitro) with a
system prompt built from live site config, sponsor queue, and strict
guardrails (no income claims, seed-phrase warnings, Telegram fallback).
Rate-limited per IP. Without OPENROUTER_API_KEY set, or on any API
error, the widget transparently falls back to the built-in knowledge
base, so the chat always works.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Self-contained assistant (no external services) with a knowledge base
covering the strategy, levels, costs, wallet setup, funding, joining,
training videos, and live current-sponsor/queue data; falls back to
the configured Telegram group link when it can't answer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Videos loudness-normalized to -16 LUFS (originals were ~-33 LUFS).
- Static file serving rewritten to stream with HTTP Range support so
video seeking works; .mp4/.webm MIME types added.
- Training nav links on homepage and /start, plus a first-time callout
on /start; training page views tracked per source in admin analytics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CSS and JS are now served no-cache like HTML so style/script updates
apply on normal refresh instead of waiting out a 1-hour browser cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- track.js captures first-touch source per session (utm_source/src param
or external referrer domain) and logs bridge/start page views.
- Join clicks now carry the source; all events aggregate per-source in
data/analytics.json on the persistent volume.
- Admin: new Traffic & Conversions card with funnel totals (bridge ->
start -> join click rates) and a per-source breakdown table.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keeps the current sponsor card above the fold; the roadmap stays
above the fold on the bridge homepage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>