Catch eligibility: catcher needs level >= the level the buyer is LEAVING, not the level being bought

Matches _payUpline (level > levelIndex, levelIndex = buyer.level-1). The old
depth+1 rule told #21 (Culmen) it could not catch #49's Apex buy; #21 is #49's
4th matrix upline and does catch it. Fixed in the owner alert, coaching scan,
dashboard pipeline, AI prompt, leader digest, chatbot and how-pay-works copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-01 10:51:30 -05:00
parent dcc8202efb
commit 747977b368
7 changed files with 23 additions and 18 deletions
+14 -10
View File
@@ -602,10 +602,12 @@ function getOwnerUpgradeNeeds(ids) {
(function walk(n, depth) {
if (!n) return;
if (depth >= 1 && (n.level || 1) === depth) {
// catcher must be AT the level being bought (depth+1), not the buyer's
// pre-upgrade level — verified on-chain: #6 was passed at exactly the
// pre-upgrade level on #8's Fabrica buy (2026-08-14)
const eligible = pQual && pLevel >= depth + 1;
// Contract: _payUpline(levelIndex = buyer.level-1) pays the first
// non-skipped upline with level > levelIndex, i.e. level >= the level
// the buyer is LEAVING (= depth). The 2026-08-14 "#6 passed on #8's
// Fabrica buy" was a structural skip (#6 is #8's gen-1), not a level
// test — the old `depth + 1` rule demanded one rung too many.
const eligible = pQual && pLevel >= depth;
if (!eligible) items.push({ memberId: n.id, depth, amount: (costs.up[n.tier === 2 ? 2 : 1] || [])[depth - 1] || 0 });
}
walk(n.left, depth + 1); walk(n.right, depth + 1);
@@ -615,7 +617,7 @@ function getOwnerUpgradeNeeds(ids) {
const atMin = items.filter(i => i.depth === minDepth);
needs.push({
id, level: pLevel, levelName: levelName(pLevel), qualified: pQual,
neededLevel: minDepth + 1, neededLevelName: levelName(minDepth + 1),
neededLevel: minDepth, neededLevelName: levelName(minDepth),
members: atMin.map(i => i.memberId),
amountAtRisk: +atMin.reduce((s, i) => s + i.amount, 0).toFixed(2),
reason: pQual ? 'upgrade' : 'qualify'
@@ -738,8 +740,10 @@ function nextOpenPosition(rootId, exclude) {
}
// Coaching radar: triage every member below `rootId` into actionable tiers.
// - atRisk: money forming in their leg that they can't catch yet (corrected
// rule: catcher must be qualified AND at the level being bought)
// - atRisk: money forming in their leg that they can't catch yet (contract
// rule: catcher must be qualified AND at or above the level the buyer is
// leaving — a member at depth D pays on their upgrade OUT of level D, so the
// catcher needs level >= D)
// - rollForward: qualified but still Scintilla — entry rewards already cover
// the Ascensus upgrade that catches their directs' first payments
// - oneAway: one direct short of qualifying (a placement fixes them)
@@ -754,15 +758,15 @@ function getCoachingScan(rootId, maxItems = 15) {
const m = state.members[id]; const lvl = m.level || 1, q = (m.directCount || 0) >= 2;
let missing = 0, minDepth = 0, fromIds = [];
(function walk(nid, depth) { const mm = state.members[nid]; if (!mm) return;
if (depth >= 1 && (mm.level || 1) === depth && !(q && lvl >= depth + 1)) {
if (depth >= 1 && (mm.level || 1) === depth && !(q && lvl >= depth)) {
const amt = (costs.up[mm.tier === 2 ? 2 : 1] || [])[depth - 1] || 0;
if (amt) { missing += amt; fromIds.push(nid); if (!minDepth || depth < minDepth) minDepth = depth; }
}
if (depth < 16) { if (mm.l) walk(mm.l, depth + 1); if (mm.r) walk(mm.r, depth + 1); } })(id, 0);
if (missing > 0) atRisk.push({ id, level: lvl, levelName: levelName(lvl), qualified: q,
directCount: m.directCount || 0, atRiskPol: +missing.toFixed(2), fromIds: fromIds.slice(0, 6),
need: q ? 'upgrade' : 'qualify', neededLevel: q ? minDepth + 1 : null,
neededLevelName: q ? levelName(minDepth + 1) : null,
need: q ? 'upgrade' : 'qualify', neededLevel: q ? minDepth : null,
neededLevelName: q ? levelName(minDepth) : null,
earnedPol: +(m.earnedPol || 0).toFixed(2),
upgradeCost: q ? +(((costs.up[m.tier === 2 ? 2 : 1] || [])[lvl - 1]) || 0).toFixed(2) : null });
if (q && lvl === 1) rollForward.push({ id, earnedPol: +(m.earnedPol || 0).toFixed(2),
+1 -1
View File
@@ -76,7 +76,7 @@
{k:['spillover','spill over','spill','under me but not qualified','people under me','not my direct','passed over','missed payment','skipped','why am i not qualified'],
a:()=>`<strong>Spillover</strong> happens when someone's sponsor already has both matrix slots full — the smart contract then places the new member in the next open slot further down, which can be under YOU. Spillover fills your matrix and sets up future upgrade payments to your position, but it does <strong>not</strong> count toward your qualification: only people who join using <em>your</em> ID are your directs. That's why you can see 2 under you and still show 1/2. And important: upgrade payments only stop at positions that are qualified (2 directs) AND at the required level — otherwise the payment passes you by to the next eligible upline. Check your position on your <a href="/my">Member Dashboard</a> — spillover placements are tagged there.`},
{k:['how do i get paid','how do i earn','commission','commissions','how payments work','how does the money','payout','payouts','pay flow','when do i get paid','how do i make money','income','two ways','how you get paid'],
a:()=>`Two ways money reaches your position — the full diagram is at <a href="/how-pay-works">rmcircle.team/how-pay-works</a>. <strong>(1) Entry rewards:</strong> when a direct joins under your link you get their entry reward (about 326 POL at Premium) and you keep it — on every direct you bring. <strong>(2) Upgrade payments:</strong> each person below you pays you once, at the ONE level that matches how far below you they sit — someone 1 layer below pays you when they hit Ascensus, 2 layers below pays you at Fabrica, 3 at Culmen, and so on. To catch each, you must be at that level yourself and qualified, so stay one level ahead of your team. No income is guaranteed.`},
a:()=>`Two ways money reaches your position — the full diagram is at <a href="/how-pay-works">rmcircle.team/how-pay-works</a>. <strong>(1) Entry rewards:</strong> when a direct joins under your link you get their entry reward (about 326 POL at Premium) and you keep it — on every direct you bring. <strong>(2) Upgrade payments:</strong> each person below you pays you once, at the ONE level that matches how far below you they sit — someone 1 layer below pays you when they hit Ascensus, 2 layers below pays you at Fabrica, 3 at Culmen, and so on. To catch each, you must be qualified and at or above the level that person is LEAVING — layer 1's Ascensus buy needs you at Scintilla (qualified), layer 3's Culmen buy needs you at Fabrica or higher — so keep your level at or above your team's deepest active layer. No income is guaranteed.`},
{k:['tier','standard','premium tier','standard tier','premium vs standard','which tier','half','smaller payment','less than expected','why is my payment'],
a:()=>`There are two tiers. <strong>Premium</strong> is what our whole team builds at (${pol()} POL entry) — full payments. <strong>Standard</strong> costs about half and pays/earns half at every level. So if a payment ever comes in smaller than expected, it usually came from a Standard-tier position below you. Your tier is <strong>set when you join and can't be changed later</strong> (upgrading advances your level, not your tier), so always join <strong>Premium</strong> and make sure the people you bring on do too. Full breakdown: <a href="/how-pay-works">how-pay-works</a>.`},
{k:['dashboard','my dashboard','my page','my position','my team','check my','see my','pipeline','my stats','alerts','notify me','email me','get notified','message','messages','contact my sponsor','contact my upline','contact my downline','reach my team'],
+1 -1
View File
@@ -58,7 +58,7 @@
</g>
</svg>
</div>
<p style="color:var(--muted);line-height:1.65;margin:14px 0 0"><strong style="color:var(--text)">To catch each one, you must be at that level yourself</strong> (and qualified). Layer 3's Culmen payment only stops at you if you're at Culmen — otherwise it passes up to the next eligible position. That's why the rule is: <strong style="color:var(--text)">stay one level ahead of your team's deepest active layer.</strong></p></div>
<p style="color:var(--muted);line-height:1.65;margin:14px 0 0"><strong style="color:var(--text)">To catch each one, you must be at or above the level that person is leaving</strong> (and qualified). Layer 3's Culmen payment only stops at you if you're at Fabrica or higher — otherwise it passes up to the next eligible position. That's why the rule is: <strong style="color:var(--text)">keep your level at or above your team's deepest active layer.</strong></p></div>
<div class="card" style="margin-top:20px;border-color:rgba(78,214,203,.45)"><div class="eyebrow" style="color:var(--teal)">Beyond the two streams</div><h2 style="margin:6px 0 10px">Your position is also a <span class="gold">license to the toolkit.</span></h2>
<p style="color:var(--muted);line-height:1.65;margin:0 0 10px">The two streams above are how money moves. This is the part that has value whether or not a single payment ever arrives: <strong style="color:var(--text)">every paid position comes with the team's marketing toolkit</strong> — and each level you climb extends the license further.</p>
+2 -1
View File
@@ -511,7 +511,8 @@
if(depth>=1){
if(lvl===depth){
const amt=(up[tier]||[])[depth-1];
if(amt)ready.push({id:n.id,depth,tier,amt,toLevel:LEVELS[depth]||('Level '+(depth+1)),needLevel:depth+1});
// catcher needs level >= the level the buyer is LEAVING (= depth), per _payUpline
if(amt)ready.push({id:n.id,depth,tier,amt,toLevel:LEVELS[depth]||('Level '+(depth+1)),needLevel:depth});
}else if(lvl<depth)building.push({id:n.id,depth,steps:depth-lvl});
else passedCount.n++;
}
+1 -1
View File
@@ -48,7 +48,7 @@
'<td>' + (r.upgradeCost ? n(r.upgradeCost) : '—') + '</td></tr>';
}).join('');
out.push('<div class="l-sec"><h2>Money forming they can\'t catch</h2>' +
'<div class="why">A position only catches an upgrade payment if it is qualified <em>and</em> already at or above the level being bought. These people have activity underneath them that is passing them by — the fastest, kindest conversation you can have this week.</div>' +
'<div class="why">A position only catches an upgrade payment if it is qualified <em>and</em> already at or above the level the buyer is leaving. These people have activity underneath them that is passing them by — the fastest, kindest conversation you can have this week.</div>' +
'<div class="table-wrap"><table class="l-tbl"><thead><tr><th>Position</th><th>Level</th><th>What they need</th><th>POL passing them</th><th>Earned</th><th>Upgrade cost</th></tr></thead><tbody>' +
rows + '</tbody></table></div></div>');
}
+3 -3
View File
@@ -67,11 +67,11 @@ FACTS:
- Strategy: enter RM Circle dApp at Premium tier (${c.premiumEntryPol || 362} POL on Polygon Mainnet, chain ID 137, POL is the gas token). Each member gets 2 directs to become "qualified". Their personal invite link (rmcircle.team/join/<their-id>) NEVER retires: it's a MOVING LINK built into the site — once the member is qualified it automatically routes each new signup to the next position in their leg that needs a direct, so members keep promoting one link forever and their promotion qualifies their team. Their personal effort shifts to helping their 2 get their 2 — a position only qualifies through its own directs. If a signup lands straight on a qualified position's raw ID anyway (the dApp path), present it as a BONUS, not a rule violation: it still pays that member the full entry reward and spills downward into the first open slot in their leg (depth). Spillover never qualifies the people below.
- First team goal: 30 properly placed positions (2+4+8+16), then 32, 64, 128 and beyond.
- 8 Premium levels in order: Scintilla, Ascensus, Fabrica, Culmen, Apex, Fastigium, Vertex, Corona. Everyone starts at Scintilla. Upgrade as quickly as practical, ideally with earned POL; the first two payments at each level help fund the next upgrade. Stay aware of your active downline's levels so you don't fall behind and miss payments.
- SPILLOVER: when a sponsor's two matrix slots are full, the contract places new members in the next open slot further down (left to right) — possibly under someone else. Spillover fills that member's matrix and sets up future upgrade income to their position, but does NOT count toward qualification: only people who join using a member's own ID are their directs. Upgrade payments travel up the MATRIX (not who-referred-whom) and only stop at positions that are qualified (2 directs) AND already at the level being bought — otherwise the payment passes them by to the next eligible upline. Members can see their own matrix, spillover tags, and payments at https://rmcircle.team/my
- SPILLOVER: when a sponsor's two matrix slots are full, the contract places new members in the next open slot further down (left to right) — possibly under someone else. Spillover fills that member's matrix and sets up future upgrade income to their position, but does NOT count toward qualification: only people who join using a member's own ID are their directs. Upgrade payments travel up the MATRIX (not who-referred-whom) and only stop at positions that are qualified (2 directs) AND at or above the level the buyer is LEAVING (a qualified Scintilla catches their matrix children's Ascensus buys; a Culmen catches an Apex buy from 4 layers down) — otherwise the payment passes them by to the next eligible upline. Members can see their own matrix, spillover tags, and payments at https://rmcircle.team/my
- TWO SHARE LINKS (on the dashboard "Share this position" panel): (1) TEAM LINK = the default rmcircle.team/join/<id> — a MOVING link that, once the member is qualified, auto-routes new joins to the next teammate in their leg who needs directs (builds the team in order; recommended). (2) DIRECT LINK = rmcircle.team/join/<id>?direct=1 — opts OUT of rotation so every join lands DIRECTLY under that member as spillover (builds their own depth). Both pay the member the entry reward on anyone they personally bring. Recommend the Team link (team-first), but the Direct link exists for members who want to stack spillover under themselves. Angle links (?v=pocket|phone|two|graveyard) work on either.
- PAY FLOW (full diagram at https://rmcircle.team/how-pay-works): TWO income streams. (1) Entry rewards — when a direct joins under a member's link, that member gets the entry reward (~326 POL at Premium) and keeps it, on EVERY direct (not just the first two). (2) Upgrade payments — each person below you pays you ONCE, at the single level matching how far below you they sit: someone 1 layer down pays you at their Ascensus upgrade, 2 layers down at Fabrica, 3 at Culmen, 4 at Apex, and so on. To catch each one you must be at that level yourself AND qualified — so stay one level ahead of your team's deepest active layer. This is why a member can be "skipped" on a payment: it was reserved for the position at the matching depth, or they weren't leveled up in time.
- PAY FLOW (full diagram at https://rmcircle.team/how-pay-works): TWO income streams. (1) Entry rewards — when a direct joins under a member's link, that member gets the entry reward (~326 POL at Premium) and keeps it, on EVERY direct (not just the first two). (2) Upgrade payments — each person below you pays you ONCE, at the single level matching how far below you they sit: someone 1 layer down pays you at their Ascensus upgrade, 2 layers down at Fabrica, 3 at Culmen, 4 at Apex, and so on. To catch each one you must be qualified AND at or above the level that person is LEAVING (layer 1's Ascensus buy needs you at Scintilla+, layer 3's Culmen buy needs you at Fabrica+, layer 4's Apex buy needs you at Culmen+) — so keep your level at or above your team's deepest active layer. This is why a member can be "skipped" on a payment: it was reserved for the position at the matching depth, or they weren't leveled up in time.
- THE TRIPLE PLAY (optional fast-start; people ask "should I get one position or three?"): Most start with ONE position — get 2 directs, help them, duplicate (the standard path, all anyone needs). OPTIONAL alternative: buy a top position PLUS its own 2 directs at the same time. Those two count as the top's directs, so the TOP is instantly qualified (2/2) and catching upgrade pass-ups from day one; then you promote only the top position's moving link, which auto-routes new joiners to fill/qualify the positions beneath. Because ONE WALLET ADDRESS CAN ONLY HOLD ONE POSITION (blockchain rule), this needs THREE separate addresses. Foolproof = a separate wallet (or browser profile) per position. You CAN use "Add account" in one MetaMask (Account 1/2/3 are separate addresses), BUT MetaMask's account switch doesn't always follow into a connected site — if the join page still shows the old address the join reverts with "already registered", so you must confirm the NEW address is shown before signing each (or disconnect+reconnect the site with the new account). Separate wallets avoid this. HARD framing to always include: costs ~3x a single entry; ONLY money you can comfortably afford to lose; NEVER borrowed; NEVER front/fund it for someone else (it puts one person in control of positions on another's wallet); it's a faster START, not an income guarantee; and one position is perfectly fine. Never push it — present it and let them choose. UPGRADE STRATEGY for a Triple Play: most members (and the founder on #21) CONCENTRATE UPGRADES ON THE TOP position and leave wallets 2 & 3 lower — because pass-ups the lower positions aren't leveled to catch bubble UP to the first eligible position (the catcher-of-last-resort mechanic), so keeping the TOP most-leveled funnels the deep catches into the top wallet, and since you own all three the money stays in your family; upgrading all three works too but costs 3x the upgrades, so concentrating on the top is leaner. Upgrades always optional/self-paced/funded by earnings, never out of pocket. Full steps: https://rmcircle.team/how-pay-works#triple-play.
- LEVEL CAP / "does it stop at 8 levels?": there are 8 levels (Scintilla..Corona); Corona is the max LEVEL — you can't upgrade past it. But EARNING is not capped. (1) You catch an upgrade pass-up from every person in your first seven generations as they level up, and those generations hold up to 254 positions that keep filling via recruiting + spillover — one payment per person, but people keep arriving. (2) Pass-ups travel UP past anyone who can't catch them: an upgrade payment rises to the first upline who is qualified (2 directs) AND leveled high enough (level >= the level being bought), searching up to the 16-layer MAX_MATRIX_DEPTH; if nobody qualifies in range it goes to the project fee wallet. So a Corona member is the "catcher of last resort" — at max level they're eligible for every pass-up, never the bottleneck, and they catch the ones under-leveled members below them let slip. That's the mechanical reason to keep leveling up. Full explainer: https://rmcircle.team/how-pay-works#cap. Still contract mechanics, never an income promise.
- LEVEL CAP / "does it stop at 8 levels?": there are 8 levels (Scintilla..Corona); Corona is the max LEVEL — you can't upgrade past it. But EARNING is not capped. (1) You catch an upgrade pass-up from every person in your first seven generations as they level up, and those generations hold up to 254 positions that keep filling via recruiting + spillover — one payment per person, but people keep arriving. (2) Pass-ups travel UP past anyone who can't catch them: an upgrade payment rises to the first upline who is qualified (2 directs) AND leveled high enough (level >= the level the buyer is leaving), searching up to the 16-layer MAX_MATRIX_DEPTH; if nobody qualifies in range it goes to the project fee wallet. So a Corona member is the "catcher of last resort" — at max level they're eligible for every pass-up, never the bottleneck, and they catch the ones under-leveled members below them let slip. That's the mechanical reason to keep leveling up. Full explainer: https://rmcircle.team/how-pay-works#cap. Still contract mechanics, never an income promise.
- TIERS: Premium (the tier the whole team builds at, ${c.premiumEntryPol || 362} POL entry) pays and earns FULL amounts; Standard costs about half and pays/earns HALF at every level. A smaller-than-expected payment almost always came from a Standard-tier position below. Tier is fixed at registration and CANNOT be changed later (upgrading advances your LEVEL, not your tier). Always recommend joining Premium and having recruits do the same. Amount comparison at /how-pay-works.
- MEMBER DASHBOARD & ALERTS: each member has a live dashboard at https://rmcircle.team/my (enter your ID) showing position, team, payments, pipeline (incoming money forming below), a team-depth summary (members per generation below you and which level's upgrade each generation pays you at), a "Coach Your Team" panel (who in YOUR leg needs a nudge — qualified-but-not-upgraded members sitting on entry rewards, members about to miss forming payments, members one direct from qualifying — each recommendation has a one-tap "Send this nudge" button that sends a ready-written teach-forward message over the wallet-verified Messages system, delivered on-site and to Telegram if the member linked it), spillover tags, and qualification badges. Members can turn on opt-in EMAIL ALERTS there (notified when paid, and when they need to upgrade to catch incoming pay). A member's personal invite page to share is https://rmcircle.team/join/<their-id>.
- RESILIENCE ("what if the creators disappear / owner loses keys / it falls apart over time"): the contract is autonomous and immutable — NO admin action, heartbeat, or living operator is required for joins, upgrades, matrix placement, or payouts; there is no pause switch and no expiry. Verified on-chain that the founder, development, and fee-receiver wallets are ordinary wallets (EOAs), NOT smart contracts — an ordinary wallet always accepts incoming POL even if its key is lost forever, so a dead or abandoned admin wallet cannot block any member payment (only the project's OWN uncollected fee would sit idle). The contract stores no balance (every payment is delivered in the same transaction). If the owner's key were lost, only the four limited admin powers freeze in place; members are unaffected. Details in section 6 of https://rmcircle.team/contract.
+1 -1
View File
@@ -73,7 +73,7 @@ async function digest(memberId, opts) {
'You are writing a short weekly coaching digest for a leader in the RM Circle team build, about their own organisation.\n\n' +
'THE FACTS — these are read live from the smart contract. Use ONLY these. Never invent an id, a level, or a POL amount:\n' +
lines.join('\n') + '\n\n' +
'HOW THE MONEY WORKS (so your advice is correct): a member catches an upgrade payment only if they are qualified (2 personal directs) AND already at or above the level being bought. Upgrade payments travel up to the first upline who meets both tests. Entry payments go to the sponsor.\n\n' +
'HOW THE MONEY WORKS (so your advice is correct): a member catches an upgrade payment only if they are qualified (2 personal directs) AND already at or above the level the buyer is LEAVING (a member 4 generations down pays on their Apex buy and needs the catcher at Culmen or higher; a qualified Scintilla catches the Ascensus buys of both matrix children). Upgrade payments travel up to the first upline who meets both tests. Entry payments go to the sponsor.\n\n' +
'ABSOLUTE RULES:\n' +
'- Never promise, guarantee or project income. Never quote dollars — POL quantities only.\n' +
'- Never state a number that is not in the facts above.\n' +