Files
martbost 6a7c5161ff Give the top of the ladder a real prize: Team Grants + Network Intelligence
Marty's read was right — the upper tiers felt flat, and the reason is that
they scaled QUANTITY, not KIND. L1->L2 was a category change (you couldn't
write, now you can). Everything above L4 was a multiplier on a capability
already owned at L2: sound more like you, measure it, more pages, five at
once. Meanwhile the price doubles each rung — Corona costs ~17x Culmen. No
batch button is worth 17x a voice profile.

The fix is a change of axis. Every tool from L1 to L8 was a "me" tool, but
past the first levels this business isn't about you: get two, help your two,
teach them to teach. So the top now operates on the ORGANISATION.

L7 Team Grants — hand Suite capacity down to anyone in your own org.
Deliberately from a separate pool that the level grants, NOT out of the
leader's own allowance: making someone choose between equipping their team
and using their own tools means nobody ever grants anything. Recipients are
verified in-org against the contract. Grants can lift a tool the recipient's
level hasn't unlocked — that's the point, not a loophole. Being helped is
made visible to the recipient, since half the value is knowing an upline
backed you.

L8 Network Intelligence — every team ad pooled and anonymised: which angles,
headlines, creative and formats actually earn their impressions. No member
alone has enough traffic to learn anything from display; together they do.
It can't be bought, and it compounds monthly with no further work. Holds two
lines: nothing identifies anyone, and nothing under 2,000 impressions gets a
reported rate — under-evidenced rows are counted and disclosed rather than
silently dropped. The written readout is hand-authored, not generated:
these are conclusions about money, and a model paraphrasing a table is
exactly where an invented number slips in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 12:26:39 -05:00

90 lines
4.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Network Intelligence client — renders the pooled, anonymised ad results.
(function () {
'use strict';
var $ = function (id) { return document.getElementById(id); };
function esc(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
function n(v) { return Number(v || 0).toLocaleString(); }
function pct(r) { return (Number(r || 0) * 100).toFixed(3) + '%'; }
function gate(msg) {
$('iLoading').style.display = 'none';
$('iGate').style.display = 'block';
$('iGate').innerHTML = msg;
}
function tile(v, label, cls) {
return '<div class="i-tile ' + (cls || '') + '"><div class="big">' + v + '</div><div class="lab">' + label + '</div></div>';
}
function section(title, why, group, unitLabel) {
if (!group || !group.rows.length) return '';
var top = group.rows[0].rate || 1;
var rows = group.rows.map(function (r) {
var w = Math.max(2, Math.round((r.rate / top) * 100));
return '<tr><td><b>' + esc(r.label) + '</b></td>' +
'<td>' + n(r.served) + '</td>' +
'<td>' + n(r.clicks) + '</td>' +
'<td><b>' + pct(r.rate) + '</b></td>' +
'<td style="width:110px"><div class="i-bar" style="width:' + w + '%"></div></td></tr>';
}).join('');
var thin = group.thin
? '<div class="i-thin">' + group.thin + ' more not shown — under the evidence threshold (' +
n(group.thinServed) + ' impressions between them).</div>'
: '';
return '<div class="i-sec"><h2>' + esc(title) + '</h2><div class="why">' + esc(why) + '</div>' +
'<div class="table-wrap"><table class="i-tbl"><thead><tr><th>' + esc(unitLabel) +
'</th><th>Served</th><th>Clicks</th><th>Rate</th><th></th></tr></thead><tbody>' +
rows + '</tbody></table></div>' + thin + '</div>';
}
function render(d) {
var rep = d.report;
$('iLoading').style.display = 'none';
if (!rep || !rep.ready) {
gate('<b>Not enough data yet.</b> ' + esc((rep && rep.reason) || 'This fills in as the team advertises.'));
return;
}
$('iBody').style.display = 'block';
$('iTiles').innerHTML =
tile(n(rep.totals.ads), 'team ads measured', 'cool') +
tile(n(rep.totals.served), 'impressions served') +
tile(n(rep.totals.clicks), 'clicks', 'cool') +
tile(pct(rep.totals.rate), 'network click rate');
$('iReadout').innerHTML = (d.readout || []).map(function (line) {
return '<div>' + esc(line) + '</div>';
}).join('') || '<div>Not enough evidence yet to draw conclusions.</div>';
var html = '';
html += section('Format', 'Text placements against banner placements, across everything the team has run.', rep.format, 'Format');
html += section('Angle', 'Which hook the destination link carried. This is the one worth acting on — it tells you what to lead with everywhere, not just in ads.', rep.angle, 'Angle');
html += section('Banner creative', 'Which designs from the team kit are actually earning their impressions.', rep.creative, 'Design');
html += section('Banner size', 'Placement size, pooled across every design.', rep.size, 'Size');
html += section('Text ad headlines', 'Individual headlines that have run enough to be judged.', rep.headline, 'Headline');
$('iSections').innerHTML = html || '<div class="i-sec"><div class="why">Nothing has crossed the evidence threshold yet. Keep the ads running.</div></div>';
}
async function boot() {
try {
var r = await fetch('/api/public/suite-intel');
if (r.status === 401) { gate('You’re not signed in yet. <a href="/suite" style="color:var(--gold);font-weight:700">Open the Suite</a> and connect the wallet that holds your position, then come back.'); return; }
if (r.status === 403) {
var g = await r.json();
gate((g.error || 'Not open for this position yet.') + ' <a href="/suite" style="color:var(--gold);font-weight:700">See your Suite</a>.');
return;
}
if (!r.ok) { gate('Could not read the network just now — try again shortly.'); return; }
render(await r.json());
} catch (e) {
gate('Connection hiccup — reload to try again.');
}
}
document.addEventListener('DOMContentLoaded', boot);
})();