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>
This commit is contained in:
martbost
2026-08-18 16:40:22 -05:00
parent 9dbe7eddcb
commit b66d3a50e8
5 changed files with 43 additions and 4 deletions
+21
View File
@@ -122,6 +122,7 @@
?`<div class="table-wrap"><table class="table" style="min-width:520px"><thead><tr><th>When</th><th>From member</th><th>For</th><th>Amount</th></tr></thead><tbody>${inc.map(p=>`<tr><td>${date(p.ts)}</td><td>#${p.fromId}</td><td>${esc(p.desc)}</td><td><strong>${fmt(p.pol)} POL</strong></td></tr>`).join('')}</tbody></table></div>`
:'<div class="empty">No payments yet — they appear here the moment they land on-chain.</div>';
renderNextStep(d);
renderGens(d);
renderPipeline(d);
renderAlerts(d);
renderShare(d);
@@ -136,6 +137,26 @@
}catch(e){return ''}
}
const LEVELS=['Scintilla','Ascensus','Fabrica','Culmen','Apex','Fastigium','Vertex','Corona'];
// Team depth — members per generation below this position, with the level
// whose upgrade routes each generation's payment to this position (gen D
// pays on the upgrade OUT of level D, i.e. buying level D+1).
function renderGens(d){
const el=document.getElementById('dGens');if(!el)return;
const root=d.subtree;
if(!root||(!root.left&&!root.right)){el.innerHTML='';return;}
const gens=[];let layer=[root];
while(layer.length&&gens.length<60){
const next=[];
layer.forEach(n=>{if(n.left)next.push(n.left);if(n.right)next.push(n.right);});
if(!next.length)break;gens.push(next.length);layer=next;
}
const rows=gens.map((c,i)=>{
const cap=Math.pow(2,i+1);
const pays=i<7?`pays you at their <strong style="color:var(--text)">${LEVELS[i+1]}</strong> upgrade`:'beyond the 8 pay levels';
return `<div style="display:flex;align-items:center;gap:10px;margin:5px 0;font-size:13px;flex-wrap:wrap"><span style="width:46px;color:var(--muted)">Gen ${i+1}</span><div class="progress-line" style="flex:1;min-width:90px;height:9px"><span style="width:${Math.min(100,Math.round(100*c/cap))}%"></span></div><span style="width:88px;text-align:right"><strong>${c}</strong><span style="color:var(--muted)">${cap<=1024?' of '+cap:''}</span></span><span class="micro" style="color:var(--muted);width:230px">${pays}</span></div>`;
}).join('');
el.innerHTML=`<div style="border-top:1px solid var(--line);padding-top:12px"><small style="text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-size:11px">Team depth — members per generation</small><div style="margin-top:8px">${rows}</div><p class="micro" style="margin:8px 0 0">Full generations duplicate: each one can hold twice the last. A generation pays this position at exactly one level — stay qualified and at that level to catch it.</p></div>`;
}
// "My Next Step" — the single clearest action + the level ladder + a funded
// badge (server tells us funded true/false; it never sends the raw balance).
function renderNextStep(d){