Add "Your Organization vs. the Network" live stat to admin

New chain.getOrgShare(rootId) + /api/admin/org-share endpoint compute an
org's share of the whole contract by both member count and total POL
paid, from in-memory state. Admin card (default root 21, saved to
config.orgRootId, auto-loads) shows the two headline percentages, a bar,
and the member/POL breakdown. Verified: #21 org = 51.1% of members,
49.5% of POL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-15 07:07:27 -05:00
parent 026b9e5d9b
commit 7b6f629780
4 changed files with 56 additions and 2 deletions
+23 -1
View File
@@ -514,6 +514,28 @@ function getOwnerUpgradeNeeds(ids) {
return { ready: true, needs };
}
// How an organization rooted at `rootId` stacks up against the whole contract —
// share of members and share of all POL paid. Computed from in-memory state.
function getOrgShare(rootId) {
if (!state || !state.snapshotAt) return { ready: false };
const totalMembers = Object.keys(state.members).length;
let totalPol = 0; for (const m of Object.values(state.members)) totalPol += m.earnedPol || 0;
const root = getSubtree(rootId, 99);
const rm = state.members[rootId];
const base = { ready: true, rootId, totalMembers, totalPol: +totalPol.toFixed(2) };
if (!root || !rm) return { ...base, found: false };
const orgBelow = root.downCount || 0;
const orgMembers = orgBelow + 1;
const orgPol = (rm.earnedPol || 0) + (root.downPol || 0);
return {
...base, found: true, orgBelow, orgMembers,
memberPct: +(100 * orgMembers / totalMembers).toFixed(1),
belowPct: +(100 * orgBelow / totalMembers).toFixed(1),
orgPol: +orgPol.toFixed(2),
polPct: totalPol ? +(100 * orgPol / totalPol).toFixed(1) : 0
};
}
// focused income read for one position — for the admin "my positions" income view
async function getIncome(id) {
const m = await fetchMember(id);
@@ -528,4 +550,4 @@ async function getIncome(id) {
};
}
module.exports = { startIndexer, getPayoutsPublic, verifyMember, memberLookup, memberPublic, getIncome, getOwnerUpgradeNeeds, getMatrixTree, isInTeam, CONTRACT };
module.exports = { startIndexer, getPayoutsPublic, verifyMember, memberLookup, memberPublic, getIncome, getOwnerUpgradeNeeds, getOrgShare, getMatrixTree, isInTeam, CONTRACT };