Files
martbost 747977b368 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>
2026-09-01 10:51:30 -05:00

89 lines
5.0 KiB
JavaScript

// Circle Suite — Leader Ops (level 7).
//
// The coaching radar already existed in chain.js and only the admin panel could
// see it. That is backwards: the people who most need to know which of their
// legs is about to leak money are the leaders running those legs, not Marty.
// This exposes it scoped to the member's OWN organisation, and adds a written
// digest on top of the raw triage.
//
// The digest follows the team's teach-forward rule: every piece of coaching
// output has to leave the leader able to teach the same thing to their two,
// rather than making them dependent on the tool. So the digest is written as
// "here is what to say to this person and why", not "here is a number".
'use strict';
const chain = require('./chain');
const suiteAi = require('./suite-ai');
const MIN_LEVEL = 7;
// Raw triage for one leader's organisation.
function scan(memberId, maxItems) {
const s = chain.getCoachingScan(Number(memberId), Math.max(3, Math.min(25, Number(maxItems) || 12)));
if (!s || !s.ready) {
return { ready: false, reason: 'The on-chain index is still catching up — try again in a moment.' };
}
return s;
}
// Turn the triage into something a leader can act on this week.
//
// We hand the model FACTS ONLY — ids, levels, POL amounts already computed from
// the contract — and forbid it from inventing any others. Everything numeric in
// the digest has to come from the scan we pass in, because a coaching digest
// that misstates what someone is owed does real damage to a real relationship.
async function digest(memberId, opts) {
const s = scan(memberId, (opts && opts.maxItems) || 12);
if (!s.ready) throw new Error(s.reason);
const nothing = !s.totals.atRiskCount && !s.totals.rollForwardCount && !s.totals.oneAwayCount;
if (nothing) {
return {
scan: s,
text: 'Nothing needs chasing in your organisation right now — nobody is one direct short, ' +
'nobody is sitting on money they cannot catch, and nobody is qualified but still on Scintilla. ' +
'That is the quiet week you use to work on your own two.'
};
}
const lines = [];
if (s.atRisk.length) {
lines.push('PEOPLE WITH MONEY FORMING BELOW THEM THEY CANNOT CATCH YET:');
s.atRisk.slice(0, 8).forEach(function (r) {
lines.push('- Position #' + r.id + ' is ' + r.levelName + ', ' +
(r.qualified ? 'qualified' : 'NOT qualified (' + r.directCount + ' of 2 directs)') +
'. ' + r.atRiskPol + ' POL is forming below them that they cannot catch. ' +
(r.qualified
? 'They need to upgrade to ' + r.neededLevelName + ' (costs ' + r.upgradeCost + ' POL). They have earned ' + r.earnedPol + ' POL so far.'
: 'They need their 2nd direct before they can catch anything at all.'));
});
}
if (s.rollForward.length) {
lines.push('QUALIFIED BUT STILL ON SCINTILLA (their entry rewards already cover the next upgrade):');
s.rollForward.slice(0, 8).forEach(function (r) {
lines.push('- Position #' + r.id + ' has earned ' + r.earnedPol + ' POL; Ascensus costs ' + r.ascensusCost + ' POL.');
});
}
if (s.oneAway.length) {
lines.push('ONE DIRECT SHORT OF QUALIFYING (a single placement fixes them):');
lines.push('- ' + s.oneAway.slice(0, 10).map(function (r) { return '#' + r.id; }).join(', '));
}
const instruction =
'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 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' +
'- Do not shame anyone. These are real people and the leader has to talk to them tomorrow.\n\n' +
'TEACH-FORWARD RULE (this is the team doctrine and it matters most): the leader should finish reading able to TEACH this to their own two, not just to act on it themselves. So for each recommendation, give the leader the words to use and the reason behind them, so they can hand the same conversation down.\n\n' +
'FORMAT: 200-320 words of plain prose. Open with the single most urgent thing. Then walk through what to say to whom, in priority order. Close with one sentence on what to teach their two this week. No headings, no bullet symbols, no markdown, no preamble.';
const text = await suiteAi.generateRaw(instruction);
return { scan: s, text: String(text || '').trim() };
}
module.exports = { scan, digest, MIN_LEVEL };