Commit Graph

52 Commits

Author SHA1 Message Date
martbost 34480d444e Dashboard: let members see what a nudge actually says before and after sending
A member sent a nudge to #102, then went looking for what had gone out. The
only feedback was a small "Delivered to their dashboard" note, so she checked
her clipboard - which still held the unrelated "Copy plain-English summary"
text describing her OWN position. She reasonably concluded the nudge had sent
her position instead of the recipient's.

It had not: the message log shows #34 -> #102 carrying #102's own numbers.
The feature was right and the feedback was wrong, which is its own kind of
bug - a member who cannot verify what they sent will assume the worst.

Every nudge now has a Preview button that names the recipient and shows the
exact text before sending, and on success the panel shows what was sent and
to whom rather than a bare "Delivered".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 09:42:59 -05:00
martbost 25eddf19c4 Dashboard: show what an upgrade buys, not just what it costs
The upgrade panel showed a price, a funded badge and a button. Nothing on it
said what the member would get. 53 of 87 qualified members in the org are
parked at Ascensus, and a panel that reads as a bill is part of why.

It now leads with what the rung unlocks, in the member's own numbers: the
generation it extends reach to, how many people they already have sitting
there, and what each of those pays when they climb. genCounts already existed
in getOrgShare; this just points it at the member instead of at the admin.

The line that matters most is arithmetic, not persuasion: because every rung
costs exactly twice the last, the first catch at the new level is exactly
double what the upgrade cost. That is Lesson 8's whole argument, and the
panel now makes it where the decision is actually taken rather than leaving
it in a lesson nobody opens at the right moment.

Wrapped in try/catch — if the org walk fails the panel renders as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 05:18:10 -05:00
martbost 962f0c8892 Stop offering "Connect Telegram" to members who are already connected
Janie linked successfully and the dashboard kept showing the Connect button,
so a working link looked like a failed one — and she had no way to tell which.

The Messages panel had no idea about link state: msg-inbox never reported it.
It now returns tgLinked (from tgbot.memberChat) on the response the panel
already fetches, so this costs no extra request. Linked members get a
confirmation telling them where their pings arrive and how to open the Mini
App, instead of a button asking them to do something already done.

Third variant today of the same failure: the interface not knowing a state it
could easily have known, and the member left guessing. The bot had it too —
telling an already-linked member their code had expired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 07:05:26 -05:00
martbost 9f3f28c4bf Connect Telegram: stop relying on window.open inside wallet browsers
Janie can now sign in from Trust's DApp browser but cannot link Telegram.
Cause: the handler called window.open(url,'_blank'), and wallet DApp browsers
routinely block programmatic window.open. The call does nothing, no error is
raised, and the member is left staring at an unchanged screen.

Now the button fetches the link and then renders a real anchor for the member
to tap — an actual tap is handled by the OS, which is what launches the
Telegram app — plus a "copy the link" button with an execCommand fallback for
webviews that refuse both.

Third failure today from the same root assumption: that members are in a
normal browser. They are usually in someone's webview.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 06:22:43 -05:00
martbost 8964dfcf97 Detect in-app browsers — the actual reason #34 could not connect
Janie's screenshot showed the X / chevron / share / kebab chrome of TELEGRAM'S
in-app browser, not Trust's DApp browser. She tapped her sponsor's link in a
Telegram chat, Telegram opened it in its own webview, and that webview can
never hold a wallet. The page said "no wallet in this browser", she said she
was using Trust — both true, completely at cross purposes.

Our advice made it worse: "open your wallet's browser and type the address" is
useless to someone whose whole reason for being on the page is that they
tapped a link.

Now we name the browser they are actually in — Telegram, Facebook, Instagram,
LINE, Messenger, X, or a generic Android WebView — say plainly that it cannot
hold a wallet and that this is not their fault, and give them the one useful
thing: a button that copies the address to the clipboard so they can paste it
into Trust. There is an execCommand fallback because older webviews have no
clipboard API, and leaving a button that silently does nothing would be worse
than not having one.

Detection deliberately requires the absence of window.ethereum before calling
something an in-app browser: wallet browsers ARE WebViews, and those are
exactly the ones that work. Verified against Telegram, Android WebView, Trust
(correctly ignored) and mobile Safari (correctly ignored).

This will hit far more members than Janie — every link tapped inside a chat
app lands in the same trap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 06:18:35 -05:00
martbost 90b03c16f9 Member pages: house heading treatment; clearer no-wallet message
Two things Marty raised.

1. Member pages did not look like the rest of the site. The byline is now the
   gold uppercase eyebrow used above every other h1, the heading is larger and
   tighter with the last beat in gold (house style is "Team <gold>Grants</gold>"),
   and the subhead steps up from 18px to a fluid 19-22px in a brighter colour.
   The headline is model-written so the gold split cannot be hand-picked —
   goldTail() takes the final two words, or one on a short line. Everything is
   escaped before the span is added; the only markup is ours.

2. The "no wallet found" error listed five wallet names and described a DApp
   tab without saying the thing that matters: you are in the wrong browser,
   and here is the address to type. It now says exactly that, names the page
   address, and warns that Trust on iPhone has no browser at all any more —
   previously those members were reading instructions they could not follow.

Diagnosed from a real case (#34): the company dApp at thermcircle.com supports
WalletConnect, so it connects from any browser; this site is injected-provider
only, so it needs the wallet's own browser. That is the whole difference, and
WalletConnect is the actual fix — this is the stopgap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 05:42:58 -05:00
martbost ad5c5721aa Wallet-connect resilience: contract costs are immutable constants, so bake verified wei fallbacks for when the wallet's internal RPC fails (MetaMask iOS 'Load failed'); friendlier retry message on network hiccups
join-now.js entry price + my.js upgrade table. Reported by Neville's team overnight 8/28.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 04:03:18 -05:00
martbost df5f94573e Printable flyers feature: 4 colorful personalized flyer designs with member QR + tear-off tabs for offline promotion; /flyers route, tools + dashboard links, chatbot + AI prompt synced 2026-08-26 16:55:50 -05:00
martbost 4b53dd5326 Direct link option: opt out of moving-link rotation to build personal spillover (Team link default, Direct link alternate) 2026-08-26 14:24:32 -05:00
martbost 1f5bcd688f how-pay-works: What each level opens up scaling table (illustration, not a promise) + dashboard link 2026-08-26 06:00:31 -05:00
martbost be129a46a4 Fix SIWE chain-mismatch: switch wallet to Polygon 137 before sign-in and members-area unlock 2026-08-26 05:36:26 -05:00
martbost b923bc18bc Dashboard level ladder: show POL upgrade cost under each level (live from contract, USD in tooltip) 2026-08-26 05:22:30 -05:00
martbost 6cf78a37b7 Wallet discovery: detect Phantom (window.phantom.ethereum) + legacy providers[]
Phantom exposes its EVM provider at window.phantom.ethereum and does not always
fire EIP-6963, so the picker never saw it. probeInjected() now folds in Phantom
and any window.ethereum.providers[] entries (deduped by identity + name) for
both pick() and list(). Phantom added to the mobile in-app-browser hint and the
dashboard no-wallet message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 05:14:57 -05:00
martbost 0ee7063a76 Wallet help: SafePal + any-wallet in-app-browser path (not just MetaMask/Trust)
Mobile users on SafePal/Coinbase/Rabby had no route in — the deep-link help
only offered MetaMask + Trust. Added a wallet-agnostic instruction (open your
wallet app -> Browser/DApp tab -> type the join URL) that works via the
injected provider our EIP-6963 picker already resolves; join-now fills the
sponsor path into the hint. Dashboard no-wallet message made wallet-agnostic
and names SafePal. No guessed SafePal deep-link scheme (unverified).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:18:46 -05:00
martbost 86ed87510b Coach panel: one-tap Send-this-nudge buttons on every recommendation
Each coach card now carries a pre-written, situation-specific teach-forward
message (all four recommendation kinds) sent over the existing wallet-verified
Messages rails: msg-send plus the Telegram bridge. When not signed in, an
inline prompt appears and the page smooth-scrolls to the Messages card.
Chatbot canned answer and AI prompt synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 07:20:23 -05:00
martbost 6ac1bcab55 Telegram companion bot, phase 1
New tgbot.js (raw Bot API, zero deps, private-chats only so the
group feeds are untouched): wallet-verified linking via dashboard
deep-link codes, personal payout + joined-on-your-link DMs, a
message bridge that delivers site messages natively in Telegram
with reply-to-answer routing (matrix-line permissions enforced by
the existing messages.js rules), and links/msg/help commands.
Webhook self-registers; secret derived from the token. Config key
companionBotToken overrides the feed bot token when Marty creates
a dedicated bot. Dashboard Messages panel gains Connect Telegram;
chatbot + AI prompt synced.
2026-08-22 19:39:55 -05:00
martbost 267d8cda1d Complete The Circle Method + productize the business-in-a-box
- Modules 2 (Help Your Two) and 3 (Teach the Teachers) live on the
  training page: six Marty-voiced lessons, coming-soon card retired,
  anchor ids on all ten lesson cards.
- Coach panel and pipeline now prescribe lessons per situation
  (L2/L3/L7/L8 chips) - Lesson 9's routing table as buttons.
- Chatbot + AI prompt know the full ten-lesson course and the
  situation-to-lesson routing rule, plus the business-in-a-box
  product answer.
- New printable: /weekly-rhythm (Lesson 10's 20-minute routine +
  4-week tracker, personalized QR), cross-linked from dashboard and
  fast-start.
- "Business in a box" section on the join page and home page names
  the full toolkit: course, promo arsenal, printables, AI coach,
  live dashboard, public engine.
2026-08-22 10:55:39 -05:00
martbost d936093c56 Add the printable 48-Hour Fast Start sheet
/fast-start: one-page checklist that personalizes with the member's
ID, invite link, and a scannable QR of /join/<id> when opened from
their dashboard (or with ?id=). Print stylesheet flips it to clean
black-on-white letter format; floating translate/chat widgets are
now excluded from printing on every page. Dashboard share card
links to it; chatbot + AI prompt synced.
2026-08-21 12:08:05 -05:00
martbost d60e8c6807 Show a USD equivalent next to Earned below you
Server keeps an hourly-cached POL/USD spot price (CoinGecko, 8s
timeout, last-known fallback) and rides it on the member API. The
org bar adds a dollar tile with the rate it used; hidden when no
price is known. Display-only - never used in on-chain math.
2026-08-20 16:27:15 -05:00
martbost 9f66412f8c Show the whole-organization totals above the matrix view
New org bar at the top of the Your team panel: total members below
(full-depth rollup), generations deep, qualified count, and POL
earned below. Chatbot canned answer + AI prompt updated in sync.
2026-08-20 16:16:22 -05:00
martbost 8533079425 Teach the stalled-member answer everywhere it can come up
A member below you pausing on an upgrade never blocks money - payments
pass UP through them to the next eligible position and everything
below keeps flowing. Bake that explanation into: the dashboard
pipeline panel (micro-note when building rows exist), the chatbot
(canned answer + AI system-prompt objection entry), and the coaching
skill docs.
2026-08-20 15:45:59 -05:00
martbost 34dc04a9fc Training Video 7: the Member Dashboard full walkthrough (Marty's recording, web-compressed 74MB to 32MB) + chatbot sync + Coach card links to it as the teach-forward reference
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 08:26:39 -05:00
martbost bf7e9b7ea5 Share card rebuilt for person-to-person referrals: always-present personal QR (moving link handles rotation), tap-to-fullscreen scan mode, guidance adapts to 2/2; render pipeline hardened so one panel error can never blank later panels
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 07:33:19 -05:00
martbost 8841e9d718 Tools page auto-personalization: dashboard hands off ?id=, every post/swipe (copy payload AND visible preview) swaps the bare main-domain link for the member's /join/<id> link; sticky via localStorage; green confirmation banner
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 07:14:45 -05:00
martbost 0754a858c3 Fix stale dashboard right after own tx: fresh=1 cache bypass (one-shot via sessionStorage flag) set on upgrade success and post-join redirect
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 15:36:08 -05:00
martbost 70fc321c3e On-dashboard upgrades: qualified members upgrade their level right from /my/<id> - ownership enforced by matching the connected wallet to the position's account, exact BigInt cost read live via getAllCosts, MoonPay assist when underfunded, wallet-app deep links on mobile
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 15:30:50 -05:00
martbost 9a1833f2b0 Wallet-verified member messaging (matrix-lines permissions, admin visibility)
- messages.js: challenge/personal_sign/recover auth (vendored pinned
  js-sha3 0.9.3 + noble-secp256k1 1.7.1, server-side only; self-tested
  positive + tamper cases), 30d HttpOnly sessions, message store on the
  volume, matrix-line permissions (your downline direct or broadcast, your
  upline chain - nothing else, so spam is impossible by construction),
  daily rate limits (30 direct / 3 broadcasts), 1500-char plain text
- chain.js: memberIdByAccount (wallet -> position for sign-in)
- API: msg-challenge/-verify/-me/-inbox/-send/-read public + msg-unread
  (count only, no auth) + admin/messages (full visibility, disclosed to
  members in the UI)
- Dashboard: Messages card with unread bell, one-tap wallet sign-in,
  inbox with auto-read, compose with to-ID or whole-team broadcast
- Admin: Member Messages review table
- Chatbot canned answer + AI system prompt updated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 13:31:31 -05:00
martbost f0a35a0127 Coach card: raise row cap 8 -> 10 so high-value entries like a funded at-risk member aren't trimmed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 07:07:13 -05:00
martbost a3fbd1b2a9 Teach-forward framing across all coaching surfaces (founders' doctrine)
Every coaching output now ends by teaching the recipient how to teach:
point them at the Coach Your Team panel on THEIR own dashboard and tell
them to run the same play for their two.

- Member dashboard dCoach footer: "you're not coaching two people - you're
  teaching two coaches"; easy-win rows add "show them how you spotted it"
- Admin Coaching Radar: teach-forward rule footer
- AI chat system prompt: COACHING DOCTRINE section so chat answers frame
  guidance teach-forward

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 05:35:43 -05:00
martbost a835291eab Coaching Radar: live downline triage in admin + member dashboards
- chain.js getCoachingScan(rootId): classifies everyone below a root into
  atRisk (POL forming they can't catch - corrected bought-level rule),
  rollForward (qualified-at-Scintilla with entry rewards covering Ascensus),
  and oneAway (1/2 directs)
- Admin: GET /api/admin/coaching?root= (name-decorated) + "Coaching Radar"
  panel with tiered who/what-to-say/POL-at-stake rows, auto-loaded
- Member dashboards: memberPublic now returns .coach scoped to the member's
  own leg; new "Coach your team" card shows the same triage so every member
  coaches their own team - computed live, no snapshots or cron needed
- Chatbot canned answer + AI system prompt updated to describe the panel

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 05:15:45 -05:00
martbost 9966dc1728 Fix off-by-one in catch-eligibility: catcher must be AT the bought level
The pipeline widget, owner upgrade alerts, and the org routing/leak map all
treated a position as eligible to catch a payment at the buyer's PRE-upgrade
level (level >= depth). Verified against on-chain history: position 6, at
exactly the pre-upgrade level (Ascensus) and qualified, was passed over on
position 8's Fabrica buy - so the contract requires the catcher to be at the
level being BOUGHT (depth+1), matching the "stay one level ahead" doctrine.

- chain.js getOwnerUpgradeNeeds: eligible now pLevel >= depth+1; neededLevel
  reported as the bought level (was one low, so alerts would have stayed
  silent in exactly the situation they exist for)
- chain.js getOrgRouting catcher(): same correction in the routing simulation
- my.js pipeline: needLevel/eligible/summary-text ladder corrected; warnings
  now name the right level

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 16:54:07 -05:00
martbost b66d3a50e8 Team-depth breakdown: members per generation on admin org panel + member dashboard
- chain.js getOrgShare now returns genCounts (breadth-first members per
  generation below the root)
- Admin "Your Organization vs. the Network" panel renders a Gen 1..N bar list
  with fill-vs-capacity (2^n slots)
- Member dashboard "Your team" card gains a Team Depth section computed from
  the subtree client-side, labeling each generation with the level whose
  upgrade pays that position (gen D pays at the level D+1 buy)
- AI chat system prompt updated to describe the new dashboard section

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 16:40:22 -05:00
martbost 629df6336c Wire the join funnel to the live /join-now self-enroll page
/join-now now honors ?ref=<id> (resolves that member's moving-link joinTarget;
falls back to the global rotation sponsor). Repointed: /start 'Join With Current
Sponsor' -> /join-now; /my pitch buttons -> /join-now?ref=<id>; invite page
/join/<id> join button -> /join-now?ref=<id>; bare /join redirect -> /join-now.
'Get Started' learn CTAs still go to /start for onboarding. When the flag is off,
/join-now gracefully redirects to /start, so the wiring is safe either way.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-18 07:37:19 -05:00
martbost 436306f4d0 /my: default to pitch on link visits + big Join button above the fold
- default tab now: shared /my/<id> link -> Team Build pitch; form lookup /
  returning member on bare /my / #dash link -> dashboard (replaces the flaky
  "have you seen this ID before" heuristic that dumped returning prospects
  straight into the dashboard).
- added a big gold "Join the Team" CTA in the hero (right column), above the
  fold, so a sold visitor can join without scrolling past the video.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 08:39:52 -05:00
martbost 45797bdf9a Rebuild /my as a two-purpose tabbed page
Turns the member page into a persistent, tabbed dual-purpose page:
- Persistent context strip: "Member #X's RM Circle page · Verified · Qualified"
- Tab 1 "The Team Build": pitch for promoted-link visitors — hook, embedded
  overview video, 3 steps, live proof (member's real on-chain numbers), Join
  under #X CTA. Persistent (replaces the dismissible cold-intro banner).
- Tab 2 "Position Dashboard": the full dashboard as-is (facts, plan, matrix,
  pipeline, alerts, share, payments, lineage).
- Default: cold visitor opens on the pitch, the member opens on their dashboard;
  both always one tap apart. Retired the coldIntro banner + its handler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 08:31:07 -05:00
martbost 800397cbdb Beef up /my cold-visitor "Start here" panel for promoted-link traffic
The dashboard serves two audiences — the member and prospects who click a
promoted link. Expanded the cold-visitor intro into a proper "New here? Start
here" panel at the top: what it is + 3 get-started steps + CTAs (join under this
member / watch training / strategy), and reframes the member detail below as
live proof. Member's own view still hides it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 06:45:43 -05:00
martbost a3e9d05f5d Dashboard 'My Next Step' panel + funded badge
Adds a synthesized next-step panel to /my: the level ladder (you-are-here →
upgrade-next), the single clearest action (qualify vs upgrade), and a funded
badge that checks the member's wallet against their next upgrade cost.

Privacy: the wallet balance is checked server-side (chain.balanceOf via
eth_getBalance) and ONLY a funded true/false is returned — the raw balance is
never exposed on the ID-addressable dashboard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 06:33:59 -05:00
martbost 76c55fe4c2 Sweep all self-references to rmcircle.team (SEO/OG/canonical/chatbot)
Domain migration go-forward: replaced every hardcoded rmcircle.saasy.top
across public/*.html (canonical, og:url, og:image, twitter tags),
chat.js (chatbot answer URLs + linkify self-link matcher), my.js, and
server.js (member-page OG injection, unsubUrl, chat system prompt) with
rmcircle.team. Old domain still serves everything; canonical now points
search engines + social previews at the new primary domain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 05:32:13 -05:00
martbost 0f5630e6d0 Disclaimer page, self-service member alerts, and admin login lockout
- /disclaimer: independent-resource, affiliate, earnings, risk, and
  not-advice disclosures; linked from all footers.
- Self-service alerts: members opt in with their email on /my/:id to get
  "you've been paid" + "upgrade needed" emails for their own position
  (same watcher as the owner alerts, extended). Signed unsubscribe link
  (/unsubscribe?id=&t=HMAC), on-chain-registration check, rate-limited,
  masked-email status, confirmation email.
- Admin login: timing-safe compare + per-IP lockout (8 fails -> 15 min,
  escalating). Previously unlimited/brute-forceable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 14:45:57 -05:00
martbost 77310f8974 Add "Copy plain-English summary" to the pipeline widget
Generates a chat-ready, per-member explainer of the upgrade/generation
payment structure — the recurring "will I miss upgrades?" question
answered from that member's real position: their spot, the one rule
(each layer pays you once at one level), their ladder with amounts and
which layers they're already eligible for, an honest "you miss it only
if you fall behind" note, and a calibrated next move (no false urgency —
distinguishes a layer that's close from one still climbing). One click
copies it for pasting into Telegram/chat; works for any member by ID.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 12:52:01 -05:00
martbost eba405abac Add "Your pipeline" widget to member dashboards
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>
2026-08-14 11:08:07 -05:00
martbost dcb3fe4d43 Give cold visitors context on member dashboards
/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>
2026-08-14 08:41:57 -05:00
martbost 29e0d6e791 Personal invite pages (/join/<id>) + auto-count queue directs from the chain
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>
2026-08-14 08:18:30 -05:00
martbost 532cb18b68 Split submissions into rotation vs leg paths — decided by the chain
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>
2026-08-14 05:39:02 -05:00
martbost d9ac9c9806 Settle the doctrine: recommend retiring at 2/2, frame spillover as bonus
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>
2026-08-13 18:48:20 -05:00
martbost f0991c651b Finish spillover copy corrections in chat and share card
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>
2026-08-13 18:24:03 -05:00
martbost 72c8f137ae Correct spillover teaching across all site copy
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>
2026-08-13 18:22:59 -05:00
martbost 130fc42c45 Teach spillover in the matrix views
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>
2026-08-13 15:13:22 -05:00
martbost 6a9cd96b8c Qualified dashboards promote the next unqualified position in their leg
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>
2026-08-13 14:58:31 -05:00
martbost 350d50798f Member dashboard: drill-down tree, list view, legend, and strategy-aware referral tool
- "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>
2026-08-13 14:53:06 -05:00