Expand ecash explorer capabilities
Add Fedimint discovery, dual SQLite/Postgres storage, richer review handling, and generated social imagery.
This commit is contained in:
+38
-8
@@ -55,18 +55,48 @@ export function bayesianScore(m: ScoreInput, priorMean: number, now: number): nu
|
||||
return Math.round(score * 1000) / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Three tiers, and the middle one exists for federations.
|
||||
*
|
||||
* `announced` is a Fedimint status: nothing has ever confirmed the thing is running, so
|
||||
* it cannot sit with the confirmed-online rows — but it is not evidence of being down
|
||||
* either, so it must not sink to the bottom with the rows a check actually failed on.
|
||||
* Not knowing belongs between knowing and knowing otherwise.
|
||||
*
|
||||
* A Cashu mint is never `announced`, so this is exactly the two-tier order it always
|
||||
* had for them.
|
||||
*/
|
||||
function healthRank(status: string): number {
|
||||
if (status === 'offline') return 2;
|
||||
if (status === 'announced') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default sort: every online mint before every offline one, then by score descending.
|
||||
* Offline mints must stay findable (people need to reach them to review them), they
|
||||
* just never appear above a live mint.
|
||||
*/
|
||||
export function compareMints<T extends { status: string; score: number; review_count: number }>(
|
||||
a: T,
|
||||
b: T,
|
||||
): number {
|
||||
const aOff = a.status === 'offline' ? 1 : 0;
|
||||
const bOff = b.status === 'offline' ? 1 : 0;
|
||||
if (aOff !== bOff) return aOff - bOff;
|
||||
export function compareMints<
|
||||
T extends { status: string; score: number; review_count: number; host?: string },
|
||||
>(a: T, b: T): number {
|
||||
const aRank = healthRank(a.status);
|
||||
const bRank = healthRank(b.status);
|
||||
if (aRank !== bRank) return aRank - bRank;
|
||||
if (b.score !== a.score) return b.score - a.score;
|
||||
return b.review_count - a.review_count;
|
||||
if (b.review_count !== a.review_count) return b.review_count - a.review_count;
|
||||
|
||||
/*
|
||||
* A final tiebreak on the slug, so two indistinguishable rows still have an order.
|
||||
*
|
||||
* Without it the winner is whatever the database happened to return first, which is a
|
||||
* different answer on SQLite and on Postgres — the same data served in two orders, and
|
||||
* a nightly rebuild that reshuffles rows for no reason. It went unnoticed while ties
|
||||
* were rare (two unreviewed mints); federations made it the common case, since every
|
||||
* one that nobody has reviewed scores exactly the prior.
|
||||
*
|
||||
* Optional in the type because the ranking checks compare bare score objects that have
|
||||
* no slug, and there is nothing to tiebreak in a two-element fixture.
|
||||
*/
|
||||
return (a.host ?? '').localeCompare(b.host ?? '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user