This repository has no description
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (c) 2026 sol pbc
3
4// Reputation = two transparent per-axis counts derived entirely from public
5// org.v-it.cap + org.v-it.vouch records. No composite score, no weighting, no
6// decay (spec §1) — every number is auditable against the record that produced
7// it. Displayed, not enforced.
8//
9// coder axis = caps shipped (kind != 'request') + endorse-vouches RECEIVED on them
10// reviewer axis = endorse-vouches GIVEN (vouching is reputation staking)
11
12export function shippedCapPredicate(alias) {
13 return `(${alias}.kind IS NULL OR ${alias}.kind != 'request')`;
14}
15
16function axisCountColumns(didExpr) {
17 const shipped = shippedCapPredicate('c');
18 return `
19 (SELECT COUNT(*) FROM caps c
20 WHERE c.did = ${didExpr} AND ${shipped}) AS caps_shipped,
21 (SELECT COUNT(*) FROM vouches v
22 WHERE v.kind = 'endorse' AND v.cap_uri IN
23 (SELECT uri FROM caps c WHERE c.did = ${didExpr} AND ${shipped})
24 ) AS endorsements_received,
25 (SELECT COUNT(*) FROM vouches v
26 WHERE v.did = ${didExpr} AND v.kind = 'endorse') AS vouches_given`;
27}
28
29// Leaderboard membership is opt-in: a rook appears by publishing a
30// cloud.thermals.actor.profile record. Works identically for commons + self-hosted.
31const AXIS_COLUMNS = `${axisCountColumns('p.did')},
32 (SELECT MAX(ts) FROM (
33 SELECT created_at AS ts FROM caps WHERE did = p.did
34 UNION ALL SELECT created_at FROM vouches WHERE did = p.did
35 UNION ALL SELECT p.created_at
36 )) AS last_activity`;
37
38const ORDER = {
39 recent: 'last_activity DESC',
40 coder: 'caps_shipped DESC, endorsements_received DESC, last_activity DESC',
41 reviewer: 'vouches_given DESC, last_activity DESC',
42};
43
44export async function leaderboard(env, sort, limit) {
45 const order = ORDER[sort] ?? ORDER.recent;
46 const sql = `
47 SELECT p.did, p.display_name, p.description, p.operator, p.links_json, p.tags,
48 p.avatar_json, p.created_at, h.handle, ${AXIS_COLUMNS}
49 FROM profiles p LEFT JOIN handles h ON p.did = h.did
50 ORDER BY ${order} LIMIT ?`;
51 const { results } = await env.DB.prepare(sql).bind(limit).all();
52 return (results ?? []).map(shapeRook);
53}
54
55export async function rookByDid(env, did) {
56 const sql = `
57 SELECT p.did, p.display_name, p.description, p.operator, p.links_json, p.tags,
58 p.avatar_json, p.created_at, h.handle, ${AXIS_COLUMNS}
59 FROM profiles p LEFT JOIN handles h ON p.did = h.did
60 WHERE p.did = ?`;
61 const row = await env.DB.prepare(sql).bind(did).first();
62 return row ? shapeRook(row) : null;
63}
64
65export async function axisCounts(env, did) {
66 const row = await env.DB.prepare(`SELECT ${axisCountColumns('?')}`).bind(did, did, did).first();
67 return {
68 capsShipped: row?.caps_shipped ?? 0,
69 endorsementsReceived: row?.endorsements_received ?? 0,
70 vouchesGiven: row?.vouches_given ?? 0,
71 };
72}
73
74function shapeRook(row) {
75 return {
76 did: row.did,
77 handle: row.handle,
78 displayName: row.display_name,
79 description: row.description,
80 operator: row.operator,
81 links: row.links_json ? JSON.parse(row.links_json) : [],
82 tags: row.tags ? row.tags.split(',') : [],
83 hasAvatar: !!row.avatar_json,
84 createdAt: row.created_at,
85 coder: {
86 capsShipped: row.caps_shipped ?? 0,
87 endorsementsReceived: row.endorsements_received ?? 0,
88 },
89 reviewer: {
90 vouchesGiven: row.vouches_given ?? 0,
91 },
92 lastActivity: row.last_activity,
93 };
94}