Circle Suite: complete the ladder — every paid level now unlocks live software

Four new tools, so no tier is a placeholder any more:

L4 Voice Profile (/suite/voice) — five short answers that ride along with
every Copy Engine and Email Engine generation. It sits BEFORE the compliance
block in the prompt on purpose: a personal voice must never be able to talk
the model out of the honesty rules. suite-email builds its own prompt, so the
profile is threaded in there separately or email would keep sounding generic
while the Copy Engine sounded like the member.

L5 Split Tester (/suite/split) — 2-3 variants launched as one test with the
impressions split evenly, then click counters compared. Deliberately
conservative: it will not declare a winner until both arms have real volume
AND the leader is clearly ahead, because a 3-click gap on 400 impressions is
noise. A genuine tie is reported as a tie, which is useful information too.
A failed arm rolls back the whole test rather than leaving half of it running.
Apex is the right home for it — that is where impressions jump to 50,000.

L6 Funnel Factory (/suite/funnel) — extra named pages at /p/<id>/<slug>, so a
leader can run one page per audience and point different ads at each. Missing
slugs fall back to the member's main page, same no-dead-ends rule as /p/<id>.

L7 Leader Ops (/suite/leader) — the coaching radar already existed in chain.js
and only admin could see it, which was backwards: the leaders running those
legs need it more than anyone. Now scoped to the member's own organisation,
with a written plan built on contract-read facts only. Follows the
teach-forward rule — the digest gives the leader words to hand down, not just
numbers to act on.

Tile copy across the wall and the payout alerts now describes what actually
exists rather than what was sketched. suite-tools.js was stale in both
directions (it still had the Traffic Desk at L5 and L3 not live).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-28 10:49:36 -05:00
parent 8380696574
commit 3f8d23d66c
17 changed files with 1525 additions and 22 deletions
+88
View File
@@ -0,0 +1,88 @@
// 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 being bought. 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 };